# HG changeset patch # User Gilles Duboscq # Date 1432827845 -7200 # Node ID 28cbfacd051832aa7e5862acec4a66f2edd34503 # Parent 107300758a4ed3bb921866cea6dca05cb67d8cd8# Parent 47c5e0903d065856b2eac8054f3de9413cd617d2 Merge diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java Thu May 28 17:44:05 2015 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.api.code; -import java.io.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -32,9 +31,7 @@ * where to find the local variables, operand stack values and locked objects of the bytecode * frame(s). */ -public class BytecodeFrame extends BytecodePosition implements Serializable { - - private static final long serialVersionUID = -345025397165977565L; +public class BytecodeFrame extends BytecodePosition { /** * An array of values representing how to reconstruct the state of the Java frame. This is array diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodePosition.java Thu May 28 17:44:05 2015 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.api.code; -import java.io.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -33,9 +32,7 @@ * system to reconstruct a source-level stack trace for exceptions and to create * {@linkplain BytecodeFrame frames} for deoptimization. */ -public class BytecodePosition implements Serializable { - - private static final long serialVersionUID = 8633885274526033515L; +public class BytecodePosition { private final BytecodePosition caller; private final ResolvedJavaMethod method; @@ -109,4 +106,15 @@ public BytecodePosition getCaller() { return caller; } + + /** + * Adds a caller to the current position returning the new position. + */ + public BytecodePosition addCaller(BytecodePosition link) { + if (getCaller() == null) { + return new BytecodePosition(link, getMethod(), getBCI()); + } else { + return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI()); + } + } } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Thu May 28 17:44:05 2015 +0200 @@ -294,6 +294,9 @@ */ public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) { MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI()); + assert sb.charAt(sb.length() - 1) == ']'; + sb.deleteCharAt(sb.length() - 1); + sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']'); if (frame.values != null && frame.values.length > 0) { sb.append(NEW_LINE); String table = tabulateValues(frame); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Thu May 28 17:44:05 2015 +0200 @@ -25,27 +25,23 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static java.util.Collections.*; -import java.io.*; import java.util.*; +import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; import com.oracle.graal.api.meta.Assumptions.Assumption; -import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; import com.oracle.graal.api.meta.*; /** * Represents the output from compiling a method, including the compiled machine code, associated * data and references, relocation information, deoptimization information, etc. */ -public class CompilationResult implements Serializable { - - private static final long serialVersionUID = -1319947729753702434L; +public class CompilationResult { /** * Represents a code position with associated additional information. */ - public abstract static class Site implements Serializable { + public abstract static class Site { - private static final long serialVersionUID = -8214214947651979102L; /** * The position (or offset) of this site with respect to the start of the target method. */ @@ -74,7 +70,6 @@ */ public static class Infopoint extends Site implements Comparable { - private static final long serialVersionUID = 2479806696381720162L; public final DebugInfo debugInfo; public final InfopointReason reason; @@ -124,8 +119,6 @@ */ public static final class Call extends Infopoint { - private static final long serialVersionUID = 1440741241631046954L; - /** * The target of the call. */ @@ -183,9 +176,7 @@ /** * Represents some external data that is referenced by the code. */ - public abstract static class Reference implements Serializable { - - private static final long serialVersionUID = 4841246083028477946L; + public abstract static class Reference { @Override public abstract int hashCode(); @@ -196,8 +187,6 @@ public static final class ConstantReference extends Reference { - private static final long serialVersionUID = 5841121930949053612L; - private final VMConstant constant; public ConstantReference(VMConstant constant) { @@ -233,8 +222,6 @@ public static final class DataSectionReference extends Reference { - private static final long serialVersionUID = 9011681879878139182L; - private boolean initialized; private int offset; @@ -281,7 +268,6 @@ */ public static final class DataPatch extends Site { - private static final long serialVersionUID = 5771730331604867476L; public Reference reference; public DataPatch(int pcOffset, Reference reference) { @@ -314,9 +300,8 @@ * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to * enhance a disassembly of the code. */ - public abstract static class CodeAnnotation implements Serializable { + public abstract static class CodeAnnotation { - private static final long serialVersionUID = -7903959680749520748L; public final int position; public CodeAnnotation(int position) { @@ -342,10 +327,6 @@ */ public static final class CodeComment extends CodeAnnotation { - /** - * - */ - private static final long serialVersionUID = 6802287188701961401L; public final String value; public CodeComment(int position, String comment) { @@ -384,8 +365,6 @@ */ public static final class JumpTable extends CodeAnnotation { - private static final long serialVersionUID = 2222194398353801831L; - /** * The low value in the key range (inclusive). */ @@ -434,7 +413,6 @@ */ public static final class ExceptionHandler extends Site { - private static final long serialVersionUID = 4897339464722665281L; public final int handlerPos; ExceptionHandler(int pcOffset, int handlerPos) { @@ -468,7 +446,6 @@ */ public static final class Mark extends Site { - private static final long serialVersionUID = 3612943150662354844L; public final Object id; public Mark(int pcOffset, Object id) { @@ -625,11 +602,10 @@ } /** - * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the assumptions made during - * compilation. + * Gets the assumptions made during compilation. */ - public Collection getAssumptions() { - return assumptions == null ? Collections.emptyList() : Arrays.asList(assumptions); + public Assumption[] getAssumptions() { + return assumptions; } /** @@ -664,15 +640,14 @@ } /** - * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the methods whose bytecodes - * were used as input to the compilation. + * Gets the methods whose bytecodes were used as input to the compilation. * * @return {@code null} if the compilation did not record method dependencies otherwise the * methods whose bytecodes were used as input to the compilation with the first element * being the root method of the compilation */ - public Collection getMethods() { - return methods == null ? null : Arrays.asList(methods); + public ResolvedJavaMethod[] getMethods() { + return methods; } public DataSection getDataSection() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java Thu May 28 17:44:05 2015 +0200 @@ -24,7 +24,6 @@ import static com.oracle.graal.api.meta.MetaUtil.*; -import java.io.*; import java.nio.*; import java.util.*; import java.util.function.*; @@ -34,9 +33,7 @@ import com.oracle.graal.api.code.DataSection.Data; import com.oracle.graal.api.meta.*; -public final class DataSection implements Serializable, Iterable { - - private static final long serialVersionUID = -1375715553825731716L; +public final class DataSection implements Iterable { @FunctionalInterface public interface DataBuilder { @@ -77,9 +74,7 @@ } } - public static final class Data implements Serializable { - - private static final long serialVersionUID = -719932751800916080L; + public static final class Data { private int alignment; private final int size; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Thu May 28 17:44:05 2015 +0200 @@ -64,6 +64,13 @@ } /** + * Returns the name of this code blob. + */ + public String getName() { + return name; + } + + /** * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 * otherwise. */ diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Thu May 28 17:44:05 2015 +0200 @@ -32,8 +32,6 @@ */ public final class RegisterValue extends AllocatableValue { - private static final long serialVersionUID = 7999341472196897163L; - private final Register reg; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java Thu May 28 17:44:05 2015 +0200 @@ -31,8 +31,6 @@ */ public final class StackLockValue extends AbstractValue implements JavaValue { - private static final long serialVersionUID = 8241681800464483691L; - private Value owner; private StackSlotValue slot; private final boolean eliminated; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Thu May 28 17:44:05 2015 +0200 @@ -30,8 +30,6 @@ */ public final class StackSlot extends StackSlotValue { - private static final long serialVersionUID = -7725071921307318433L; - private final int offset; private final boolean addFrameSize; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlotValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlotValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlotValue.java Thu May 28 17:44:05 2015 +0200 @@ -30,8 +30,6 @@ */ public abstract class StackSlotValue extends AllocatableValue { - private static final long serialVersionUID = 5106407801795483337L; - public StackSlotValue(LIRKind lirKind) { super(lirKind); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Thu May 28 17:44:05 2015 +0200 @@ -33,8 +33,6 @@ */ public final class VirtualObject extends AbstractValue implements JavaValue { - private static final long serialVersionUID = -2907197776426346021L; - private final ResolvedJavaType type; private Value[] values; private final int id; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualStackSlot.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,6 @@ */ public abstract class VirtualStackSlot extends StackSlotValue { - private static final long serialVersionUID = 2823688688873398219L; private final int id; public VirtualStackSlot(int id, LIRKind lirKind) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Thu May 28 17:44:05 2015 +0200 @@ -312,6 +312,25 @@ } } + @Test + public void isJavaLangObjectInitTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); + assertTrue(method.isJavaLangObjectInit()); + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isJavaLangObjectInit()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + Constructor key = e.getKey(); + if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { + assertTrue(m.isJavaLangObjectInit()); + } else { + assertFalse(m.isJavaLangObjectInit()); + } + } + } + private Method findTestMethod(Method apiMethod) { String testName = apiMethod.getName() + "Test"; for (Method m : getClass().getDeclaredMethods()) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java Thu May 28 17:44:05 2015 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.api.meta; -import java.io.*; - /** * This object holds probability information for a set of items that were profiled at a specific * BCI. The precision of the supplied values may vary, but a runtime that provides this information @@ -34,9 +32,7 @@ * @param the class of the items that are profiled at the specific BCI and for which * probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod. */ -public abstract class AbstractJavaProfile, U> implements Serializable { - - private static final long serialVersionUID = 5493379044459116749L; +public abstract class AbstractJavaProfile, U> { private final double notRecordedProbability; private final T[] pitems; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractProfiledItem.java Thu May 28 17:44:05 2015 +0200 @@ -22,15 +22,11 @@ */ package com.oracle.graal.api.meta; -import java.io.*; - /** * A profiled type that has a probability. Profiled types are naturally sorted in descending order * of their probabilities. */ -public abstract class AbstractProfiledItem implements Comparable>, Serializable { - - private static final long serialVersionUID = 7838575753661305744L; +public abstract class AbstractProfiledItem implements Comparable> { protected final T item; protected final double probability; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractValue.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractValue.java Thu May 28 17:44:05 2015 +0200 @@ -22,14 +22,10 @@ */ package com.oracle.graal.api.meta; -import java.io.*; - /** * Abstract base class for values. */ -public abstract class AbstractValue implements Serializable, Value, KindProvider { - - private static final long serialVersionUID = -6909397188697766469L; +public abstract class AbstractValue implements Value, KindProvider { public static final AllocatableValue ILLEGAL = Value.ILLEGAL; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java Thu May 28 17:44:05 2015 +0200 @@ -28,8 +28,6 @@ */ public abstract class AllocatableValue extends AbstractValue implements JavaValue, KindProvider { - private static final long serialVersionUID = 153019506717492133L; - public static final AllocatableValue[] NONE = {}; public AllocatableValue(LIRKind lirKind) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java Thu May 28 17:44:05 2015 +0200 @@ -22,25 +22,20 @@ */ package com.oracle.graal.api.meta; -import java.io.*; import java.lang.invoke.*; import java.util.*; /** * Class for recording assumptions made during compilation. */ -public final class Assumptions implements Serializable, Iterable { - - private static final long serialVersionUID = 5152062717588239131L; +public final class Assumptions implements Iterable { /** * Abstract base class for assumptions. An assumption assumes a property of the runtime that may * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing * {@link NoFinalizableSubclass Object.finalize()}). */ - public abstract static class Assumption implements Serializable { - - private static final long serialVersionUID = -1936652569665112915L; + public abstract static class Assumption { } /** @@ -68,6 +63,10 @@ return result; } + public boolean isAssumptionFree() { + return assumptions.length == 0; + } + public void add(AssumptionResult other) { Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); @@ -80,8 +79,6 @@ */ public static final class NoFinalizableSubclass extends Assumption { - private static final long serialVersionUID = 6451169735564055081L; - private ResolvedJavaType receiverType; public NoFinalizableSubclass(ResolvedJavaType receiverType) { @@ -115,8 +112,6 @@ */ public static final class ConcreteSubtype extends Assumption { - private static final long serialVersionUID = -1457173265437676252L; - /** * Type the assumption is made about. */ @@ -164,8 +159,6 @@ */ public static final class LeafType extends Assumption { - private static final long serialVersionUID = -1457173265437676252L; - /** * Type the assumption is made about. */ @@ -203,8 +196,6 @@ */ public static final class ConcreteMethod extends Assumption { - private static final long serialVersionUID = -7636746737947390059L; - /** * A virtual (or interface) method whose unique implementation for the receiver type in * {@link #context} is {@link #impl}. @@ -257,8 +248,6 @@ */ public static final class CallSiteTargetValue extends Assumption { - private static final long serialVersionUID = 1732459941784550371L; - public final CallSite callSite; public final MethodHandle methodHandle; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java Thu May 28 17:44:05 2015 +0200 @@ -63,6 +63,14 @@ JavaConstant readConstantArrayElement(JavaConstant array, int index); /** + * Reads a value from the given array at the given offset if it is a stable array. The offset + * will decoded relative to the platform addressing into an index into the array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the offset + * is out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset); + + /** * Gets the constant value of this field. Note that a {@code static final} field may not be * considered constant if its declaring class is not yet initialized or if it is a well known * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java Thu May 28 17:44:05 2015 +0200 @@ -256,16 +256,18 @@ */ static PrimitiveConstant forIntegerKind(Kind kind, long i) { switch (kind) { + case Boolean: + return forBoolean(i != 0); case Byte: - return new PrimitiveConstant(kind, (byte) i); + return forByte((byte) i); case Short: - return new PrimitiveConstant(kind, (short) i); + return forShort((short) i); case Char: - return new PrimitiveConstant(kind, (char) i); + return forChar((char) i); case Int: - return new PrimitiveConstant(kind, (int) i); + return forInt((int) i); case Long: - return new PrimitiveConstant(kind, i); + return forLong(i); default: throw new IllegalArgumentException("not an integer kind: " + kind); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaMethodProfile.java Thu May 28 17:44:05 2015 +0200 @@ -31,8 +31,6 @@ */ public final class JavaMethodProfile extends AbstractJavaProfile { - private static final long serialVersionUID = -1440572119913692689L; - public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) { super(notRecordedProbability, pitems); } @@ -43,8 +41,6 @@ public static class ProfiledMethod extends AbstractProfiledItem { - private static final long serialVersionUID = 5418813647187024693L; - public ProfiledMethod(ResolvedJavaMethod method, double probability) { super(method, probability); } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Thu May 28 17:44:05 2015 +0200 @@ -33,7 +33,6 @@ */ public final class JavaTypeProfile extends AbstractJavaProfile { - private static final long serialVersionUID = -6877016333706838441L; private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; private final TriState nullSeen; @@ -145,8 +144,6 @@ public static class ProfiledType extends AbstractProfiledItem { - private static final long serialVersionUID = 1481773321889860837L; - public ProfiledType(ResolvedJavaType type, double probability) { super(type, probability); assert type.isArray() || type.isConcrete() : type; @@ -177,4 +174,22 @@ } return buf.append(String.format("], notRecorded:%.6f>", getNotRecordedProbability())).toString(); } + + /** + * Returns {@code true} if all types seen at this location have been recorded in the profile. + */ + public boolean allTypesRecorded() { + return this.getNotRecordedProbability() == 0.0; + } + + /** + * Returns the single monormorphic type representing this profile or {@code null} if no such + * type exists. + */ + public ResolvedJavaType asSingleType() { + if (allTypesRecorded() && this.getTypes().length == 1) { + return getTypes()[0].getType(); + } + return null; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LIRKind.java Thu May 28 17:44:05 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.api.meta; +import java.util.*; + /** * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the * low level representation of the value, and a {@link #referenceMask} that describes the location @@ -133,15 +135,60 @@ */ public static LIRKind merge(Value... inputs) { assert inputs.length > 0; - for (Value input : inputs) { - LIRKind kind = input.getLIRKind(); + ArrayList kinds = new ArrayList<>(inputs.length); + for (int i = 0; i < inputs.length; i++) { + kinds.add(inputs[i].getLIRKind()); + } + return merge(kinds); + } + + /** + * @see #merge(Value...) + */ + public static LIRKind merge(Iterable kinds) { + LIRKind mergeKind = null; + + for (LIRKind kind : kinds) { + + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + if (kind.isDerivedReference()) { + /** + * Kind is a derived reference therefore the result can only be also a derived + * reference. + */ return kind; } + if (mergeKind == null) { + mergeKind = kind; + continue; + } + + if (kind.isValue()) { + /* Kind is a value. */ + if (mergeKind.referenceMask != 0) { + /* + * Inputs consists of values and references. Make the result a derived + * reference. + */ + return mergeKind.makeDerivedReference(); + } + /* Check that other inputs are also values. */ + } else { + /* Kind is a reference. */ + if (mergeKind.referenceMask != kind.referenceMask) { + /* + * Reference maps do not match so the result can only be a derived reference. + */ + return mergeKind.makeDerivedReference(); + } + } + } + assert mergeKind != null; // all inputs are values or references, just return one of them - return inputs[0].getLIRKind(); + return mergeKind; } /** @@ -277,4 +324,26 @@ LIRKind other = (LIRKind) obj; return platformKind == other.platformKind && referenceMask == other.referenceMask; } + + public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) { + if (src.equals(dst)) { + return true; + } + /* + * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals( + * dst.getPlatformKind()) but due to the handling of sub-integer at the current point + * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds. + */ + if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) { + return !src.isDerivedReference() || dst.isDerivedReference(); + } + return false; + } + + private static PlatformKind toStackKind(PlatformKind platformKind) { + if (platformKind instanceof Kind) { + return ((Kind) platformKind).getStackKind(); + } + return platformKind; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta; + +public class LineNumberTableImpl implements LineNumberTable { + + private final int[] lineNumbers; + private final int[] bci; + + public LineNumberTableImpl(int[] lineNumbers, int[] bci) { + this.lineNumbers = lineNumbers; + this.bci = bci; + } + + @Override + public int[] getLineNumberEntries() { + return lineNumbers; + } + + @Override + public int[] getBciEntries() { + return bci; + } + + @Override + public int getLineNumber(@SuppressWarnings("hiding") int bci) { + for (int i = 0; i < this.bci.length - 1; i++) { + if (this.bci[i] <= bci && bci < this.bci[i + 1]) { + return lineNumbers[i]; + } + } + return lineNumbers[lineNumbers.length - 1]; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta; + +public class LocalImpl implements Local { + + private final String name; + private final int startBci; + private final int endBci; + private final int slot; + private final JavaType type; + + public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { + this.name = name; + this.startBci = startBci; + this.endBci = endBci; + this.slot = slot; + this.type = type; + } + + @Override + public int getStartBCI() { + return startBci; + } + + @Override + public int getEndBCI() { + return endBci; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + return type; + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LocalImpl)) { + return false; + } + LocalImpl that = (LocalImpl) obj; + return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "LocalImpl"; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta; + +import java.util.*; + +public class LocalVariableTableImpl implements LocalVariableTable { + + private final Local[] locals; + + public LocalVariableTableImpl(Local[] locals) { + this.locals = locals; + } + + @Override + public Local getLocal(int slot, int bci) { + Local result = null; + for (Local local : locals) { + if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { + if (result == null) { + result = local; + } else { + throw new IllegalStateException("Locals overlap!"); + } + } + } + return result; + } + + @Override + public Local[] getLocals() { + return locals; + } + + @Override + public Local[] getLocalsAt(int bci) { + List result = new ArrayList<>(); + for (Local l : locals) { + if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { + result.add(l); + } + } + return result.toArray(new Local[result.size()]); + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Thu May 28 17:44:05 2015 +0200 @@ -54,26 +54,18 @@ */ public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); - protected final boolean immutable; - public static LocationIdentity any() { return ANY_LOCATION; } - protected LocationIdentity(boolean immutable) { - this.immutable = immutable; - } - /** * Denotes a location is unchanging in all cases. Not that this is different than the Java * notion of final which only requires definite assignment. */ - public final boolean isImmutable() { - return immutable; - } + public abstract boolean isImmutable(); public final boolean isMutable() { - return !immutable; + return !isImmutable(); } public final boolean isAny() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Thu May 28 17:44:05 2015 +0200 @@ -46,11 +46,12 @@ } } - protected final String name; + private final String name; + private final boolean immutable; private NamedLocationIdentity(String name, boolean immutable) { - super(immutable); this.name = name; + this.immutable = immutable; } /** @@ -87,6 +88,11 @@ } @Override + public boolean isImmutable() { + return immutable; + } + + @Override public String toString() { return name + (isImmutable() ? ":final" : ""); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NullConstant.java Thu May 28 17:44:05 2015 +0200 @@ -27,8 +27,6 @@ */ final class NullConstant extends AbstractValue implements JavaConstant { - private static final long serialVersionUID = 8906209595800783961L; - protected NullConstant() { super(LIRKind.reference(Kind.Object)); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PrimitiveConstant.java Thu May 28 17:44:05 2015 +0200 @@ -30,8 +30,6 @@ */ public class PrimitiveConstant extends AbstractValue implements JavaConstant, SerializableConstant { - private static final long serialVersionUID = 8787949721295655376L; - /** * The boxed primitive value as a {@code long}. For {@code float} and {@code double} values, * this value is the result of {@link Float#floatToRawIntBits(float)} and diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/RawConstant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/RawConstant.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/RawConstant.java Thu May 28 17:44:05 2015 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.api.meta; public class RawConstant extends PrimitiveConstant { - private static final long serialVersionUID = -242269518888560348L; public RawConstant(long rawValue) { super(Kind.Int, rawValue); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Thu May 28 17:44:05 2015 +0200 @@ -288,4 +288,11 @@ default boolean hasReceiver() { return !isStatic(); } + + /** + * Determines if this method is {@link java.lang.Object#Object()}. + */ + default boolean isJavaLangObjectInit() { + return getDeclaringClass().isJavaLangObject() && getName().equals(""); + } } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Thu May 28 17:44:05 2015 +0200 @@ -28,7 +28,7 @@ */ public interface Value extends KindProvider, TrustedInterface { - @SuppressWarnings("serial") AllocatableValue ILLEGAL = new AllocatableValue(LIRKind.Illegal) { + AllocatableValue ILLEGAL = new AllocatableValue(LIRKind.Illegal) { @Override public String toString() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java --- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Thu May 28 17:44:05 2015 +0200 @@ -56,15 +56,6 @@ String signature() default ""; /** - * Determines if this method should be substituted in all cases, even if inlining thinks it is - * not important. - * - * Note that this is still depending on whether inlining sees the correct call target, so it's - * only a hard guarantee for static and special invocations. - */ - boolean forced() default false; - - /** * Determines if the substitution is for a method that may not be part of the runtime. For * example, a method introduced in a later JDK version. Substitutions for such methods are * omitted if the original method cannot be found. diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Thu May 28 17:44:05 2015 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; /** * This class implements commonly used X86 code patterns. @@ -256,9 +257,14 @@ * volatile field! */ public final void movlong(AMD64Address dst, long src) { - AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4); - movl(dst, (int) (src & 0xFFFFFFFF)); - movl(high, (int) (src >> 32)); + if (NumUtil.isInt(src)) { + AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src); + } else { + AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4); + movl(dst, (int) (src & 0xFFFFFFFF)); + movl(high, (int) (src >> 32)); + } + } public final void flog(Register dest, Register value, boolean base10) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java --- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Thu May 28 17:44:05 2015 +0200 @@ -63,6 +63,7 @@ CompilationResult compResult = new CompilationResult(); byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); compResult.setTargetCode(targetCode, targetCode.length); + compResult.setTotalFrameSize(0); InstalledCode code = codeCache.addMethod(method, compResult, null, null); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java Thu May 28 17:44:05 2015 +0200 @@ -82,6 +82,13 @@ return (short) x == x; } + /** + * Determines if a given {@code long} value is the range of signed short values. + */ + public static boolean isShort(long x) { + return (short) x == x; + } + public static boolean isUShort(int s) { return s == (s & 0xFFFF); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/ConstantStackMoveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/ConstantStackMoveTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015, 2015, 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.compiler.amd64.test; + +import static org.junit.Assume.*; + +import org.junit.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.jtt.*; + +public class ConstantStackMoveTest extends LIRTest { + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + private static class LoadConstantStackSpec extends LIRTestSpecification { + protected final Object primitive; + + public LoadConstantStackSpec(Object primitive) { + this.primitive = primitive; + } + + @Override + public void generate(LIRGeneratorTool gen) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + PrimitiveConstant constantValue = JavaConstant.forBoxedPrimitive(primitive); + StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(constantValue.getLIRKind()); + // move stuff around + gen.emitMove(s1, constantValue); + gen.emitBlackhole(s1); + setResult(gen.emitMove(s1)); + } + } + + private static final class LoadConstantStackSpecByte extends LoadConstantStackSpec { + public LoadConstantStackSpecByte(byte primitive) { + super(primitive); + } + + byte get() { + return (Byte) primitive; + } + } + + private static final class LoadConstantStackSpecShort extends LoadConstantStackSpec { + public LoadConstantStackSpecShort(short primitive) { + super(primitive); + } + + short get() { + return (Short) primitive; + } + } + + private static final class LoadConstantStackSpecInteger extends LoadConstantStackSpec { + public LoadConstantStackSpecInteger(int primitive) { + super(primitive); + } + + int get() { + return (Integer) primitive; + } + } + + private static final class LoadConstantStackSpecLong extends LoadConstantStackSpec { + public LoadConstantStackSpecLong(long primitive) { + super(primitive); + } + + long get() { + return (Long) primitive; + } + } + + private static final class LoadConstantStackSpecFloat extends LoadConstantStackSpec { + public LoadConstantStackSpecFloat(float primitive) { + super(primitive); + } + + float get() { + return (Float) primitive; + } + } + + private static final class LoadConstantStackSpecDouble extends LoadConstantStackSpec { + public LoadConstantStackSpecDouble(double primitive) { + super(primitive); + } + + double get() { + return (Double) primitive; + } + } + + private static final LoadConstantStackSpecByte stackCopyByte = new LoadConstantStackSpecByte(Byte.MAX_VALUE); + private static final LoadConstantStackSpecShort stackCopyShort = new LoadConstantStackSpecShort(Short.MAX_VALUE); + private static final LoadConstantStackSpecInteger stackCopyInt = new LoadConstantStackSpecInteger(Integer.MAX_VALUE); + private static final LoadConstantStackSpecLong stackCopyLong = new LoadConstantStackSpecLong(Long.MAX_VALUE); + private static final LoadConstantStackSpecFloat stackCopyFloat = new LoadConstantStackSpecFloat(Float.MAX_VALUE); + private static final LoadConstantStackSpecDouble stackCopyDouble = new LoadConstantStackSpecDouble(Double.MAX_VALUE); + + @LIRIntrinsic + public static byte testCopyByte(LoadConstantStackSpecByte spec) { + return spec.get(); + } + + public byte testByte() { + return testCopyByte(stackCopyByte); + } + + @Test + public void runByte() throws Throwable { + runTest("testByte"); + } + + @LIRIntrinsic + public static short testCopyShort(LoadConstantStackSpecShort spec) { + return spec.get(); + } + + public short testShort() { + return testCopyShort(stackCopyShort); + } + + @Test + public void runShort() throws Throwable { + runTest("testShort"); + } + + @LIRIntrinsic + public static int testCopyInt(LoadConstantStackSpecInteger spec) { + return spec.get(); + } + + public int testInt() { + return testCopyInt(stackCopyInt); + } + + @Test + public void runInt() throws Throwable { + runTest("testInt"); + } + + @LIRIntrinsic + public static long testCopyLong(LoadConstantStackSpecLong spec) { + return spec.get(); + } + + public long testLong() { + return testCopyLong(stackCopyLong); + } + + @Test + public void runLong() throws Throwable { + runTest("testLong"); + } + + @LIRIntrinsic + public static float testCopyFloat(LoadConstantStackSpecFloat spec) { + return spec.get(); + } + + public float testFloat() { + return testCopyFloat(stackCopyFloat); + } + + @Test + public void runFloat() throws Throwable { + runTest("testFloat"); + } + + @LIRIntrinsic + public static double testCopyDouble(LoadConstantStackSpecDouble spec) { + return spec.get(); + } + + public double testDouble() { + return testCopyDouble(stackCopyDouble); + } + + @Test + public void runDouble() throws Throwable { + runTest("testDouble"); + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/StackStoreTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/StackStoreTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, 2015, 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.compiler.amd64.test; + +import static org.junit.Assume.*; + +import org.junit.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.jtt.*; + +public class StackStoreTest extends LIRTest { + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + private static final LIRTestSpecification stackCopy0 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind()); + StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short)); + // move stuff around + gen.emitMove(s1, a); + gen.emitMove(s2, JavaConstant.forShort(Short.MIN_VALUE)); + setResult(gen.emitMove(s1)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + private static final LIRTestSpecification stackCopy1 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind()); + StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short)); + // move stuff around + gen.emitMove(s1, a); + Value v = gen.emitMove(JavaConstant.forShort(Short.MIN_VALUE)); + gen.emitMove(s2, v); + setResult(gen.emitMove(s1)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + private static final LIRTestSpecification stackCopy2 = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen, Value a) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(a.getLIRKind()); + StackSlotValue s2 = frameMapBuilder.allocateSpillSlot(LIRKind.value(Kind.Short)); + // move stuff around + gen.emitMove(s2, JavaConstant.forShort(Short.MIN_VALUE)); + gen.emitMove(s1, a); + setResult(gen.emitMove(s2)); + gen.emitBlackhole(s1); + gen.emitBlackhole(s2); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static int testShortStackSlot(LIRTestSpecification spec, int a) { + return a; + } + + @SuppressWarnings("unused") + @LIRIntrinsic + public static short testShortStackSlot2(LIRTestSpecification spec, int a) { + return Short.MIN_VALUE; + } + + public int test0(int a) { + return testShortStackSlot(stackCopy0, a); + } + + @Test + public void run0() throws Throwable { + runTest("test0", 0xDEADDEAD); + } + + public int test1(int a) { + return testShortStackSlot(stackCopy1, a); + } + + @Test + public void run1() throws Throwable { + runTest("test1", 0xDEADDEAD); + } + + public int test2(int a) { + return testShortStackSlot2(stackCopy2, a); + } + + @Test + public void run2() throws Throwable { + runTest("test2", 0xDEADDEAD); + } + +} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Thu May 28 17:44:05 2015 +0200 @@ -52,6 +52,7 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; +import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.*; @@ -64,6 +65,7 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove; +import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; @@ -81,6 +83,7 @@ private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int)); private AMD64SpillMoveFactory moveFactory; + private Map categorized; private static class RegisterBackupPair { public final Register register; @@ -93,7 +96,6 @@ } private class AMD64SpillMoveFactory implements LIRGeneratorTool.SpillMoveFactory { - private Map categorized; @Override public LIRInstruction createMove(AllocatableValue result, Value input) { @@ -102,34 +104,9 @@ @Override public LIRInstruction createStackMove(AllocatableValue result, Value input) { - RegisterBackupPair backup = getScratchRegister(input.getPlatformKind()); - return new AMD64StackMove(result, input, backup.register, backup.backupSlot); + return AMD64LIRGenerator.this.createStackMove(result, input); } - private RegisterBackupPair getScratchRegister(PlatformKind kind) { - PlatformKind.Key key = kind.getKey(); - if (categorized == null) { - categorized = new HashMap<>(); - } else if (categorized.containsKey(key)) { - return categorized.get(key); - } - - FrameMapBuilder frameMapBuilder = getResult().getFrameMapBuilder(); - RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig(); - - Register[] availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters()); - assert availableRegister != null && availableRegister.length > 1; - Register scratchRegister = availableRegister[0]; - - Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch; - LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory())); - VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind); - - RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot); - categorized.put(key, value); - - return value; - } } public AMD64LIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { @@ -155,6 +132,28 @@ } } + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + protected final boolean canStoreConstant(JavaConstant c) { + // there is no immediate move of 64-bit constants on Intel + switch (c.getKind()) { + case Long: + return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); + case Double: + return false; + case Object: + return c.isNull(); + default: + return true; + } + } + protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { if (src instanceof AMD64AddressValue) { return new LeaOp(dst, (AMD64AddressValue) src); @@ -165,6 +164,42 @@ } } + protected LIRInstruction createStackMove(AllocatableValue result, Value input) { + RegisterBackupPair backup = getScratchRegister(input.getPlatformKind()); + Register scratchRegister = backup.register; + StackSlotValue backupSlot = backup.backupSlot; + return createStackMove(result, input, scratchRegister, backupSlot); + } + + protected LIRInstruction createStackMove(AllocatableValue result, Value input, Register scratchRegister, StackSlotValue backupSlot) { + return new AMD64StackMove(result, input, scratchRegister, backupSlot); + } + + protected RegisterBackupPair getScratchRegister(PlatformKind kind) { + PlatformKind.Key key = kind.getKey(); + if (categorized == null) { + categorized = new HashMap<>(); + } else if (categorized.containsKey(key)) { + return categorized.get(key); + } + + FrameMapBuilder frameMapBuilder = getResult().getFrameMapBuilder(); + RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig(); + + Register[] availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters()); + assert availableRegister != null && availableRegister.length > 1; + Register scratchRegister = availableRegister[0]; + + Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch; + LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory())); + VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind); + + RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot); + categorized.put(key, value); + + return value; + } + @Override public void emitMove(AllocatableValue dst, Value src) { append(createMove(dst, src)); @@ -252,6 +287,183 @@ return result; } + private static LIRKind toStackKind(LIRKind kind) { + if (kind.getPlatformKind() instanceof Kind) { + Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind(); + return kind.changeType(stackKind); + } else { + return kind; + } + } + + @Override + public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { + AMD64AddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(toStackKind(kind)); + switch ((Kind) kind.getPlatformKind()) { + case Boolean: + append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); + break; + case Byte: + append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); + break; + case Char: + append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); + break; + case Short: + append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); + break; + case Int: + append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); + break; + case Long: + case Object: + append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); + break; + case Float: + append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); + break; + case Double: + append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { + if (value.isNull()) { + assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; + OperandSize size = kind == Kind.Int ? DWORD : QWORD; + append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); + } else { + AMD64MIOp op = AMD64MIOp.MOV; + OperandSize size; + long imm; + + switch (kind) { + case Boolean: + case Byte: + op = AMD64MIOp.MOVB; + size = BYTE; + imm = value.asInt(); + break; + case Char: + case Short: + size = WORD; + imm = value.asInt(); + break; + case Int: + size = DWORD; + imm = value.asInt(); + break; + case Long: + size = QWORD; + imm = value.asLong(); + break; + case Float: + size = DWORD; + imm = Float.floatToRawIntBits(value.asFloat()); + break; + case Double: + size = QWORD; + imm = Double.doubleToRawLongBits(value.asDouble()); + break; + default: + throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind); + } + + if (NumUtil.isInt(imm)) { + append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); + } else { + emitStore(kind, address, asAllocatable(value), state); + } + } + } + + protected void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { + switch (kind) { + case Boolean: + case Byte: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); + break; + case Char: + case Short: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); + break; + case Int: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); + break; + case Long: + case Object: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); + break; + case Float: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); + break; + case Double: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { + AMD64AddressValue storeAddress = asAddressValue(address); + Kind kind = (Kind) lirKind.getPlatformKind(); + if (isConstant(input)) { + emitStoreConst(kind, storeAddress, asConstant(input), state); + } else { + emitStore(kind, storeAddress, asAllocatable(input), state); + } + } + + @Override + public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + LIRKind kind = newValue.getLIRKind(); + assert kind.equals(expectedValue.getLIRKind()); + Kind memKind = (Kind) kind.getPlatformKind(); + + AMD64AddressValue addressValue = asAddressValue(address); + RegisterValue raxRes = AMD64.rax.asValue(kind); + emitMove(raxRes, expectedValue); + append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); + + assert trueValue.getLIRKind().equals(falseValue.getLIRKind()); + Variable result = newVariable(trueValue.getLIRKind()); + append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); + return result; + } + + @Override + public Value emitAtomicReadAndAdd(Value address, Value delta) { + LIRKind kind = delta.getLIRKind(); + Kind memKind = (Kind) kind.getPlatformKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta))); + return result; + } + + @Override + public Value emitAtomicReadAndWrite(Value address, Value newValue) { + LIRKind kind = newValue.getLIRKind(); + Kind memKind = (Kind) kind.getPlatformKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); + return result; + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!"; + append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); + } + @Override public void emitJump(LabelRef label) { assert label != null; @@ -1055,16 +1267,39 @@ return result; } else { assert inputVal.getKind().getStackKind() == Kind.Int; - Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); - int mask = (int) CodeUtil.mask(fromBits); - append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); + + LIRKind resultKind = LIRKind.derive(inputVal); if (toBits > 32) { - Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); - emitMove(longResult, result); - return longResult; + resultKind = resultKind.changeType(Kind.Long); } else { - return result; + resultKind = resultKind.changeType(Kind.Int); } + + /* + * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD + * operations implicitly set the upper half of the register to 0, which is what we want + * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is + * sometimes one byte shorter. + */ + switch (fromBits) { + case 8: + return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal); + case 16: + return emitConvertOp(resultKind, MOVZX, DWORD, inputVal); + case 32: + return emitConvertOp(resultKind, MOV, DWORD, inputVal); + } + + // odd bit count, fall back on manual masking + Variable result = newVariable(resultKind); + JavaConstant mask; + if (toBits > 32) { + mask = JavaConstant.forLong(CodeUtil.mask(fromBits)); + } else { + mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits)); + } + append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask)); + return result; } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -47,6 +47,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java Thu May 28 17:44:05 2015 +0200 @@ -45,4 +45,6 @@ public Fields getData() { return data; } + + public abstract Fields[] getAllFields(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java Thu May 28 17:44:05 2015 +0200 @@ -48,6 +48,8 @@ */ private final Class[] types; + private final Class[] declaringClasses; + public static Fields forClass(Class clazz, Class endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) { FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset); scanner.scan(clazz, endClazz, includeTransient); @@ -59,11 +61,13 @@ this.offsets = new long[fields.size()]; this.names = new String[offsets.length]; this.types = new Class[offsets.length]; + this.declaringClasses = new Class[offsets.length]; int index = 0; for (FieldsScanner.FieldInfo f : fields) { offsets[index] = f.offset; names[index] = f.name; types[index] = f.type; + declaringClasses[index] = f.declaringClass; index++; } } @@ -77,7 +81,7 @@ public static void translateInto(Fields fields, ArrayList infos) { for (int index = 0; index < fields.getCount(); index++) { - infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index])); + infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index])); } } @@ -217,6 +221,10 @@ return other.offsets[index] == offsets[index]; } + public long[] getOffsets() { + return offsets; + } + /** * Gets the name of a field. * @@ -235,6 +243,10 @@ return types[index]; } + public Class getDeclaringClass(int index) { + return declaringClasses[index]; + } + /** * Checks that a given field is assignable from a given value. * diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java Thu May 28 17:44:05 2015 +0200 @@ -60,11 +60,13 @@ public final long offset; public final String name; public final Class type; + public final Class declaringClass; - public FieldInfo(long offset, String name, Class type) { + public FieldInfo(long offset, String name, Class type, Class declaringClass) { this.offset = offset; this.name = name; this.type = type; + this.declaringClass = declaringClass; } /** @@ -117,6 +119,6 @@ } protected void scanField(Field field, long offset) { - data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType())); + data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass())); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu May 28 17:44:05 2015 +0200 @@ -286,7 +286,7 @@ public static final OptionValue OptImplicitNullChecks = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) - public static final OptionValue OptLivenessAnalysis = new OptionValue<>(true); + public static final OptionValue OptClearNonLiveLocals = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) public static final OptionValue OptLoopTransform = new OptionValue<>(true); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/RegisterAllocationConfig.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/RegisterAllocationConfig.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/RegisterAllocationConfig.java Thu May 28 17:44:05 2015 +0200 @@ -36,6 +36,36 @@ */ public class RegisterAllocationConfig { + public static final class AllocatableRegisters { + public final Register[] allocatableRegisters; + public final int minRegisterNumber; + public final int maxRegisterNumber; + + public AllocatableRegisters(Register[] allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) { + this.allocatableRegisters = allocatableRegisters; + this.minRegisterNumber = minRegisterNumber; + this.maxRegisterNumber = maxRegisterNumber; + assert verify(allocatableRegisters, minRegisterNumber, maxRegisterNumber); + } + + private static boolean verify(Register[] allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) { + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (Register reg : allocatableRegisters) { + int number = reg.number; + if (number < min) { + min = number; + } + if (number > max) { + max = number; + } + } + assert minRegisterNumber == min; + assert maxRegisterNumber == max; + return true; + } + } + public static final String ALL_REGISTERS = ""; private static Register findRegister(String name, Register[] all) { @@ -47,7 +77,7 @@ throw new IllegalArgumentException("register " + name + " is not allocatable"); } - private static Register[] initAllocatable(Register[] registers) { + protected Register[] initAllocatable(Register[] registers) { if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) { String[] names = RegisterPressure.getValue().split(","); Register[] regs = new Register[names.length]; @@ -60,11 +90,12 @@ return registers; } - private final RegisterConfig registerConfig; - private final Map categorized = new HashMap<>(); + protected final RegisterConfig registerConfig; + private final Map categorized = new HashMap<>(); private Register[] cachedRegisters; public RegisterAllocationConfig(RegisterConfig registerConfig) { + assert registerConfig != null; this.registerConfig = registerConfig; } @@ -72,17 +103,19 @@ * Gets the set of registers that can be used by the register allocator for a value of a * particular kind. */ - public Register[] getAllocatableRegisters(PlatformKind kind) { + public AllocatableRegisters getAllocatableRegisters(PlatformKind kind) { PlatformKind.Key key = kind.getKey(); if (categorized.containsKey(key)) { - Register[] val = categorized.get(key); + AllocatableRegisters val = categorized.get(key); return val; } - - Register[] ret = registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters()); + AllocatableRegisters ret = createAllocatableRegisters(registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters())); categorized.put(key, ret); return ret; + } + protected AllocatableRegisters createAllocatableRegisters(Register[] registers) { + return new AllocatableRegisters(registers, registers[0].number, registers[registers.length - 1].number); } /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java Thu May 28 17:44:05 2015 +0200 @@ -43,6 +43,11 @@ protected abstract AbstractObjectStamp copyWith(ResolvedJavaType newType, boolean newExactType, boolean newNonNull, boolean newAlwaysNull); @Override + protected final AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + return copyWith(type, exactType, newNonNull, newAlwaysNull); + } + + @Override public Stamp unrestricted() { return copyWith(null, false, false, false); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractPointerStamp.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -45,6 +45,8 @@ return alwaysNull; } + protected abstract AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull); + @Override public int hashCode() { final int prime = 31; @@ -55,6 +57,36 @@ } @Override + public Stamp join(Stamp stamp) { + AbstractPointerStamp other = (AbstractPointerStamp) stamp; + boolean joinNonNull = this.nonNull || other.nonNull; + boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull; + if (joinNonNull && joinAlwaysNull) { + return empty(); + } else { + return copyWith(joinNonNull, joinAlwaysNull); + } + } + + @Override + public Stamp improveWith(Stamp other) { + return join(other); + } + + @Override + public Stamp meet(Stamp stamp) { + AbstractPointerStamp other = (AbstractPointerStamp) stamp; + boolean meetNonNull = this.nonNull && other.nonNull; + boolean meetAlwaysNull = this.alwaysNull && other.alwaysNull; + return copyWith(meetNonNull, meetAlwaysNull); + } + + @Override + public Stamp unrestricted() { + return copyWith(false, false); + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java --- a/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java Thu May 28 17:44:05 2015 +0200 @@ -58,7 +58,7 @@ @Test public void test3() { - testAllocation("test3snippet", 3, 1, 0); + testAllocation("test3snippet", 3, 0, 0); } public static long test3snippet(long x) { diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Thu May 28 17:44:05 2015 +0200 @@ -52,15 +52,7 @@ import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp; -import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp; -import com.oracle.graal.lir.sparc.SPARCMove.LoadDataAddressOp; -import com.oracle.graal.lir.sparc.SPARCMove.MembarOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGpVIS3; -import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp; -import com.oracle.graal.lir.sparc.SPARCMove.SPARCStackMove; -import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp; +import com.oracle.graal.lir.sparc.SPARCMove.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.sparc.*; import com.oracle.graal.sparc.SPARC.CPUFeature; @@ -82,7 +74,7 @@ @Override public LIRInstruction createStackMove(AllocatableValue result, Value input) { - return new SPARCStackMove(result, input); + return SPARCLIRGenerator.this.createStackMove(result, input); } } @@ -125,6 +117,10 @@ } } + protected LIRInstruction createStackMove(AllocatableValue result, Value input) { + return new SPARCStackMove(result, input); + } + @Override public void emitMove(AllocatableValue dst, Value src) { append(createMove(dst, src)); @@ -158,15 +154,15 @@ finalDisp += asConstant(index).asLong() * scale; indexRegister = Value.ILLEGAL; } else { + Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64); if (scale != 1) { - Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64); if (CodeUtil.isPowerOf2(scale)) { indexRegister = emitShl(longIndex, JavaConstant.forLong(CodeUtil.log2(scale))); } else { indexRegister = emitMul(longIndex, JavaConstant.forLong(scale), false); } } else { - indexRegister = asAllocatable(index); + indexRegister = asAllocatable(longIndex); } } } else { @@ -856,9 +852,10 @@ case F2D: return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input); case I2F: { - AllocatableValue convertedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float)); - moveBetweenFpGp(convertedFloatReg, input); - append(new Unary2Op(I2F, convertedFloatReg, convertedFloatReg)); + AllocatableValue intEncodedFloatReg = newVariable(LIRKind.derive(input).changeType(Kind.Float)); + moveBetweenFpGp(intEncodedFloatReg, input); + AllocatableValue convertedFloatReg = newVariable(intEncodedFloatReg.getLIRKind()); + append(new Unary2Op(I2F, convertedFloatReg, intEncodedFloatReg)); return convertedFloatReg; } case I2D: { @@ -871,9 +868,10 @@ return convertedDoubleReg; } case L2D: { - AllocatableValue convertedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double)); - moveBetweenFpGp(convertedDoubleReg, input); - append(new Unary2Op(L2D, convertedDoubleReg, convertedDoubleReg)); + AllocatableValue longEncodedDoubleReg = newVariable(LIRKind.derive(input).changeType(Kind.Double)); + moveBetweenFpGp(longEncodedDoubleReg, input); + AllocatableValue convertedDoubleReg = newVariable(longEncodedDoubleReg.getLIRKind()); + append(new Unary2Op(L2D, convertedDoubleReg, longEncodedDoubleReg)); return convertedDoubleReg; } case D2I: { @@ -1070,4 +1068,16 @@ append(new ReturnOp(Value.ILLEGAL)); } + public Value emitSignExtendLoad(LIRKind kind, Value address, LIRFrameState state) { + SPARCAddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(kind); + append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state, true)); + return result; + } + + public void emitNullCheck(Value address, LIRFrameState state) { + PlatformKind kind = address.getPlatformKind(); + assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!"; + append(new NullCheckOp(asAddressValue(address), state)); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -29,12 +29,12 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.match.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.sparc.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; /** * This class implements the SPARC specific portion of the LIR generator. @@ -106,7 +106,7 @@ Kind localToKind = toKind; return builder -> { Value address = access.accessLocation().generateAddress(builder, gen, operand(access.object())); - Value v = getLIRGeneratorTool().emitLoad(LIRKind.value(localFromKind), address, getState(access)); + Value v = getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), address, getState(access)); return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v); }; } @@ -116,4 +116,9 @@ public ComplexMatchResult signExtend(SignExtendNode root, Access access) { return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); } + + @Override + public SPARCLIRGenerator getLIRGeneratorTool() { + return (SPARCLIRGenerator) super.getLIRGeneratorTool(); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 2015, 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.compiler.test; + +import org.junit.*; + +public class BoxingTest extends GraalCompilerTest { + + public static Object boxSnippet(int arg) { + return arg; + } + + @Test + public void test0() { + test("boxSnippet", 0); + } + + @Test + public void test5() { + test("boxSnippet", 5); + } + + @Test + public void testMinus5() { + test("boxSnippet", -5); + } + + @Test + public void test300() { + test("boxSnippet", 300); + } + + @Test + public void testMinus300() { + test("boxSnippet", -300); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CopyOfVirtualizationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CopyOfVirtualizationTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, 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.compiler.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +public class CopyOfVirtualizationTest extends GraalCompilerTest { + + @Override + protected boolean checkMidTierGraph(StructuredGraph graph) { + assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph); + return super.checkMidTierGraph(graph); + } + + public byte byteCopyOfVirtualization(int index) { + byte[] array = new byte[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public short shortCopyOfVirtualization(int index) { + short[] array = new short[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public char charCopyOfVirtualization(int index) { + char[] array = new char[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public int intCopyOfVirtualization(int index) { + int[] array = new int[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public long longCopyOfVirtualization(int index) { + long[] array = new long[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public float floatCopyOfVirtualization(int index) { + float[] array = new float[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public double doubleCopyOfVirtualization(int index) { + double[] array = new double[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + public Object objectCopyOfVirtualization(int index) { + Object[] array = new Object[]{1, 2, 3, 4}; + return Arrays.copyOf(array, array.length)[index]; + } + + // @Test + public void testCopyOfVirtualization() { + test("byteCopyOfVirtualization", 3); + test("shortCopyOfVirtualization", 3); + test("charCopyOfVirtualization", 3); + test("intCopyOfVirtualization", 3); + test("longCopyOfVirtualization", 3); + test("floatCopyOfVirtualization", 3); + test("doubleCopyOfVirtualization", 3); + test("objectCopyOfVirtualization", 3); + } + + static final byte[] byteArray = new byte[]{1, 2, 3, 4}; + + public byte byteCopyOfVirtualizableAllocation() { + return Arrays.copyOf(byteArray, byteArray.length)[3]; + } + + static final short[] shortArray = new short[]{1, 2, 3, 4}; + + public short shortCopyOfVirtualizableAllocation() { + return Arrays.copyOf(shortArray, shortArray.length)[3]; + } + + static final char[] charArray = new char[]{1, 2, 3, 4}; + + public char charCopyOfVirtualizableAllocation() { + return Arrays.copyOf(charArray, charArray.length)[3]; + } + + static final int[] intArray = new int[]{1, 2, 3, 4}; + + public int intCopyOfVirtualizableAllocation() { + return Arrays.copyOf(intArray, intArray.length)[3]; + } + + static final long[] longArray = new long[]{1, 2, 3, 4}; + + public long longCopyOfVirtualizableAllocation() { + return Arrays.copyOf(longArray, longArray.length)[3]; + } + + static final float[] floatArray = new float[]{1, 2, 3, 4}; + + public float floatCopyOfVirtualizableAllocation() { + return Arrays.copyOf(floatArray, floatArray.length)[3]; + } + + static final double[] doubleArray = new double[]{1, 2, 3, 4}; + + public double doubleCopyOfVirtualizableAllocation() { + return Arrays.copyOf(doubleArray, doubleArray.length)[3]; + } + + static final Object[] objectArray = new Object[]{1, 2, 3, 4}; + + public Object objectCopyOfVirtualizableAllocation() { + return Arrays.copyOf(objectArray, objectArray.length)[3]; + } + + @Test + public void testCopyOfVirtualizableAllocation() { + test("byteCopyOfVirtualizableAllocation"); + test("shortCopyOfVirtualizableAllocation"); + test("charCopyOfVirtualizableAllocation"); + test("intCopyOfVirtualizableAllocation"); + test("longCopyOfVirtualizableAllocation"); + test("floatCopyOfVirtualizableAllocation"); + test("doubleCopyOfVirtualizableAllocation"); + test("objectCopyOfVirtualizableAllocation"); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu May 28 17:44:05 2015 +0200 @@ -321,7 +321,7 @@ result.append("\n"); for (Node node : schedule.getBlockToNodesMap().get(block)) { if (node instanceof ValueNode && node.isAlive()) { - if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) { + if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof InfopointNode)) { if (node instanceof ConstantNode) { String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); String str = name + (excludeVirtual ? "\n" : " (" + node.getUsageCount() + ")\n"); @@ -436,8 +436,8 @@ protected static class Result { - final Object returnValue; - final Throwable exception; + public final Object returnValue; + public final Throwable exception; public Result(Object returnValue, Throwable exception) { this.returnValue = returnValue; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -36,7 +36,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.options.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OnStackReplacementTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OnStackReplacementTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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.compiler.test; + +import org.junit.*; + +public class OnStackReplacementTest extends GraalCompilerTest { + + @Test + public void test1() { + test("test1Snippet"); + } + + static int limit = 10000; + + public static void test1Snippet() { + for (int i = 0; !Thread.currentThread().isInterrupted() && i < limit; i++) { + for (int j = 0; !Thread.currentThread().isInterrupted() && j < limit; j++) { + } + } + + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.common.*; diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -28,7 +28,7 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Thu May 28 17:44:05 2015 +0200 @@ -51,6 +51,7 @@ public static class TestClassInt { public int x; public int y; + public int z; public TestClassInt() { this(0, 0); @@ -68,7 +69,7 @@ @Override public boolean equals(Object obj) { TestClassInt other = (TestClassInt) obj; - return x == other.x && y == other.y; + return x == other.x && y == other.y && z == other.z; } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Thu May 28 17:44:05 2015 +0200 @@ -23,12 +23,14 @@ package com.oracle.graal.compiler.test.ea; import java.lang.ref.*; + import org.junit.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; @@ -191,6 +193,23 @@ assertTrue(graph.getNodes().filter(ReturnNode.class).first().result() == graph.getParameter(0)); } + public static int testBoxLoopSnippet(int n) { + Integer sum = 0; + for (Integer i = 0; i < n; i++) { + if (sum == null) { + sum = null; + } else { + sum += i; + } + } + return sum; + } + + @Test + public void testBoxLoop() { + testPartialEscapeAnalysis("testBoxLoopSnippet", 0, 0, BoxNode.class, UnboxNode.class); + } + @SafeVarargs protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { prepareGraph(snippet, false); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java Thu May 28 17:44:05 2015 +0200 @@ -36,15 +36,23 @@ public static int zero = 0; private static final Unsafe unsafe; - private static final long fieldOffsetX; - private static final long fieldOffsetY; + private static final long fieldOffset1; + private static final long fieldOffset2; static { unsafe = UnsafeAccess.unsafe; try { - fieldOffsetX = unsafe.objectFieldOffset(TestClassInt.class.getField("x")); - fieldOffsetY = unsafe.objectFieldOffset(TestClassInt.class.getField("y")); - assert fieldOffsetY == fieldOffsetX + 4; + long localFieldOffset1 = unsafe.objectFieldOffset(TestClassInt.class.getField("x")); + // Make the fields 8 byte aligned (Required for testing setLong on Architectures which + // does not support unaligned memory access + if (localFieldOffset1 % 8 == 0) { + fieldOffset1 = localFieldOffset1; + fieldOffset2 = unsafe.objectFieldOffset(TestClassInt.class.getField("y")); + } else { + fieldOffset1 = unsafe.objectFieldOffset(TestClassInt.class.getField("y")); + fieldOffset2 = unsafe.objectFieldOffset(TestClassInt.class.getField("z")); + } + assert fieldOffset2 == fieldOffset1 + 4; } catch (Exception e) { throw new RuntimeException(e); } @@ -57,8 +65,8 @@ public static int testSimpleIntSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putInt(x, fieldOffsetX, 101); - return unsafe.getInt(x, fieldOffsetX); + unsafe.putInt(x, fieldOffset1, 101); + return unsafe.getInt(x, fieldOffset1); } @Test @@ -68,7 +76,7 @@ public static TestClassInt testMaterializedIntSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putInt(x, fieldOffsetX, 101); + unsafe.putInt(x, fieldOffset1, 101); return x; } @@ -79,8 +87,8 @@ public static double testSimpleDoubleSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putDouble(x, fieldOffsetX, 10.1); - return unsafe.getDouble(x, fieldOffsetX); + unsafe.putDouble(x, fieldOffset1, 10.1); + return unsafe.getDouble(x, fieldOffset1); } @Test @@ -97,12 +105,12 @@ TestClassInt x; if (a) { x = new TestClassInt(0, 0); - unsafe.putDouble(x, fieldOffsetX, doubleField); + unsafe.putDouble(x, fieldOffset1, doubleField); } else { x = new TestClassInt(); - unsafe.putDouble(x, fieldOffsetX, doubleField2); + unsafe.putDouble(x, fieldOffset1, doubleField2); } - return unsafe.getDouble(x, fieldOffsetX); + return unsafe.getDouble(x, fieldOffset1); } @Test @@ -112,7 +120,7 @@ public static TestClassInt testMaterializedDoubleSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putDouble(x, fieldOffsetX, 10.1); + unsafe.putDouble(x, fieldOffset1, 10.1); return x; } @@ -126,10 +134,10 @@ public static TestClassInt testDeoptDoubleVarSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putDouble(x, fieldOffsetX, doubleField); + unsafe.putDouble(x, fieldOffset1, doubleField); doubleField2 = 123; try { - doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero; + doubleField = ((int) unsafe.getDouble(x, fieldOffset1)) / zero; } catch (RuntimeException e) { return x; } @@ -143,10 +151,10 @@ public static TestClassInt testDeoptDoubleConstantSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putDouble(x, fieldOffsetX, 10.123); + unsafe.putDouble(x, fieldOffset1, 10.123); doubleField2 = 123; try { - doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero; + doubleField = ((int) unsafe.getDouble(x, fieldOffset1)) / zero; } catch (RuntimeException e) { return x; } @@ -163,10 +171,10 @@ public static TestClassInt testDeoptLongVarSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putLong(x, fieldOffsetX, longField); + unsafe.putLong(x, fieldOffset1, longField); longField2 = 123; try { - longField = unsafe.getLong(x, fieldOffsetX) / zero; + longField = unsafe.getLong(x, fieldOffset1) / zero; } catch (RuntimeException e) { return x; } @@ -180,10 +188,10 @@ public static TestClassInt testDeoptLongConstantSnippet() { TestClassInt x = new TestClassInt(); - unsafe.putLong(x, fieldOffsetX, 0x2222222210123L); + unsafe.putLong(x, fieldOffset1, 0x2222222210123L); longField2 = 123; try { - longField = unsafe.getLong(x, fieldOffsetX) / zero; + longField = unsafe.getLong(x, fieldOffset1) / zero; } catch (RuntimeException e) { return x; } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu May 28 17:44:05 2015 +0200 @@ -223,7 +223,7 @@ public static void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend, TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) { - try (Scope s = Debug.scope("BackEnd"); DebugCloseable a = BackEnd.start()) { + try (Scope s = Debug.scope("BackEnd", schedule); DebugCloseable a = BackEnd.start()) { // Repeatedly run the LIR code generation pass to improve statistical profiling results. for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) { SchedulePhase dummySchedule = new SchedulePhase(); @@ -300,7 +300,7 @@ } try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) { - return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites); + return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig)); } catch (Throwable e) { throw Debug.handle(e); } @@ -310,11 +310,11 @@ } public static > LIRGenerationResult emitLowLevel(TargetDescription target, List codeEmittingOrder, List linearScanOrder, LIRGenerationResult lirGenRes, - LIRGeneratorTool lirGen, LIRSuites lirSuites) { + LIRGeneratorTool lirGen, LIRSuites lirSuites, RegisterAllocationConfig registerAllocationConfig) { PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen); lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, preAllocOptContext); - AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory()); + AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig); lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext); PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -113,7 +113,6 @@ } objectStates.clear(); - assert frame.validateFormat(false); return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -51,6 +51,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; @@ -194,17 +195,21 @@ } protected LIRKind getExactPhiKind(PhiNode phi) { - ArrayList values = new ArrayList<>(phi.valueCount()); + // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList. + ArrayList values = new ArrayList<>(phi.valueCount()); for (int i = 0; i < phi.valueCount(); i++) { ValueNode node = phi.valueAt(i); Value value = node instanceof ConstantNode ? ((ConstantNode) node).asJavaConstant() : getOperand(node); if (value != null) { - values.add(value); + values.add(value.getLIRKind()); } else { - assert isPhiInputFromBackedge(phi, i); + assert node instanceof ConstantNode || isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", + node, phi); + // non-java constant -> get Kind from stamp. + values.add(getLIRGeneratorTool().getLIRKind(node.stamp())); } } - LIRKind derivedKind = LIRKind.merge(values.toArray(new Value[values.size()])); + LIRKind derivedKind = LIRKind.merge(values); assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp())); return derivedKind; } @@ -212,7 +217,7 @@ private static boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) { assert derivedKind.getPlatformKind() != Kind.Object || !derivedKind.isDerivedReference(); PlatformKind phiPlatformKind = phiKind.getPlatformKind(); - assert derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind); + assert derivedKind.equals(phiKind) || derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind); return true; } @@ -238,6 +243,13 @@ for (PhiNode phi : merge.valuePhis()) { Value value = operand(phi.valueAt(pred)); assert value != null; + if (isRegister(value)) { + /* + * Fixed register intervals are not allowed at block boundaries so we introduce a + * new Variable. + */ + value = gen.emitMove(value); + } values.add(value); } return values.toArray(new Value[values.size()]); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Thu May 28 17:44:05 2015 +0200 @@ -31,13 +31,12 @@ * usually occur here. */ public class ComplexMatchValue extends AbstractValue { - private static final long serialVersionUID = -4734670273590368770L; /** * This is the Value of a node which was matched as part of a complex match. The value isn't * actually useable but this marks it as having been evaluated. */ - @SuppressWarnings("serial") public static final Value INTERIOR_MATCH = new AbstractValue(LIRKind.Illegal) { + public static final Value INTERIOR_MATCH = new AbstractValue(LIRKind.Illegal) { @Override public String toString() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java Thu May 28 17:44:05 2015 +0200 @@ -66,7 +66,7 @@ * having their inputs change are the main interesting differences. */ HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED); - StructuredGraph graphCopy = graph.copy(); + StructuredGraph graphCopy = (StructuredGraph) graph.copy(); try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) { try (Scope s2 = Debug.sandbox("WithoutMonitoring", null)) { super.run(graphCopy, context); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu May 28 17:44:05 2015 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -82,6 +83,8 @@ */ public abstract FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig); + public abstract RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig); + public abstract FrameMap newFrameMap(RegisterConfig registerConfig); public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Thu May 28 17:44:05 2015 +0200 @@ -269,9 +269,10 @@ /** * This method exists mainly to allow a debugger (e.g., Eclipse) to force dump a graph. */ - public static void forceDump(Object object, String message) { + public static void forceDump(Object object, String format, Object... args) { DebugConfig config = getConfig(); if (config != null) { + String message = String.format(format, args); for (DebugDumpHandler dumpHandler : config.dumpHandlers()) { dumpHandler.dump(object, message); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/CachedGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/CachedGraph.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 2015, 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.graph; + +import java.util.*; +import java.util.function.*; + +/** + * This class is a container of a graph that needs to be readonly and optionally a lazily created + * mutable copy of the graph. + */ +public final class CachedGraph { + + private final G readonlyCopy; + private G mutableCopy; + + private CachedGraph(G readonlyCopy, G mutableCopy) { + this.readonlyCopy = readonlyCopy; + this.mutableCopy = mutableCopy; + } + + public static CachedGraph fromReadonlyCopy(G graph) { + return new CachedGraph<>(graph, null); + } + + public static CachedGraph fromMutableCopy(G graph) { + return new CachedGraph<>(graph, graph); + } + + public G getReadonlyCopy() { + if (hasMutableCopy()) { + return mutableCopy; + } + return readonlyCopy; + } + + public boolean hasMutableCopy() { + return mutableCopy != null; + } + + @SuppressWarnings("unchecked") + public G getMutableCopy(Consumer> duplicationMapCallback) { + if (!hasMutableCopy()) { + mutableCopy = (G) readonlyCopy.copy(duplicationMapCallback); + } + return mutableCopy; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Thu May 28 17:44:05 2015 +0200 @@ -57,7 +57,7 @@ public static void translateInto(Edges edges, ArrayList infos) { for (int index = 0; index < edges.getCount(); index++) { - infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index))); + infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index))); } } @@ -547,10 +547,6 @@ } } - public long[] getOffsets() { - return this.offsets; - } - public void pushAll(Node node, NodeStack stack) { int index = 0; int curDirectCount = this.directCount; diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Thu May 28 17:44:05 2015 +0200 @@ -25,6 +25,7 @@ import static com.oracle.graal.graph.Edges.Type.*; import java.util.*; +import java.util.function.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; @@ -219,8 +220,17 @@ /** * Creates a copy of this graph. */ - public Graph copy() { - return copy(name); + public final Graph copy() { + return copy(name, null); + } + + /** + * Creates a copy of this graph. + * + * @param duplicationMapCallback consumer of the duplication map created during the copying + */ + public final Graph copy(Consumer> duplicationMapCallback) { + return copy(name, duplicationMapCallback); } /** @@ -228,9 +238,22 @@ * * @param newName the name of the copy, used for debugging purposes (can be null) */ - public Graph copy(String newName) { + public final Graph copy(String newName) { + return copy(newName, null); + } + + /** + * Creates a copy of this graph. + * + * @param newName the name of the copy, used for debugging purposes (can be null) + * @param duplicationMapCallback consumer of the duplication map created during the copying + */ + protected Graph copy(String newName, Consumer> duplicationMapCallback) { Graph copy = new Graph(newName); - copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map) null); + Map duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (Map) null); + if (duplicationMapCallback != null) { + duplicationMapCallback.accept(duplicates); + } return copy; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java Thu May 28 17:44:05 2015 +0200 @@ -47,7 +47,7 @@ public static void translateInto(InputEdges inputs, ArrayList infos) { for (int index = 0; index < inputs.getCount(); index++) { - infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.inputTypes[index], inputs.isOptional(index))); + infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index))); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Thu May 28 17:44:05 2015 +0200 @@ -241,6 +241,11 @@ return shortName; } + @Override + public Fields[] getAllFields() { + return new Fields[]{data, inputs, successors}; + } + public int[] iterableIds() { nodeIterableCount.increment(); return iterableIds; @@ -288,8 +293,8 @@ */ protected static class EdgeInfo extends FieldsScanner.FieldInfo { - public EdgeInfo(long offset, String name, Class type) { - super(offset, name, type); + public EdgeInfo(long offset, String name, Class type, Class declaringClass) { + super(offset, name, type, declaringClass); } /** @@ -317,8 +322,8 @@ final InputType inputType; final boolean optional; - public InputInfo(long offset, String name, Class type, InputType inputType, boolean optional) { - super(offset, name, type); + public InputInfo(long offset, String name, Class type, Class declaringClass, InputType inputType, boolean optional) { + super(offset, name, type, declaringClass); this.inputType = inputType; this.optional = optional; } @@ -375,7 +380,7 @@ } else { inputType = optionalInputAnnotation.value(); } - inputs.add(new InputInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class))); + inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class))); } else if (successorAnnotation != null) { if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { // NodeSuccessorList fields should not be final since they are @@ -387,7 +392,7 @@ GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field); directSuccessors++; } - successors.add(new EdgeInfo(offset, field.getName(), type)); + successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass())); } else { GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field); GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -41,7 +41,9 @@ } public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode[] args) { - b.addPush(new ForeignCallNode(foreignCalls, descriptor, args)); + ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args); + foreignCall.setBci(b.bci()); + b.addPush(foreignCall); return true; } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Thu May 28 17:44:05 2015 +0200 @@ -131,9 +131,10 @@ private final boolean eagerResolving; private final boolean omitAllExceptionEdges; + private final boolean omitAssertions; private final ResolvedJavaType[] skippedExceptionTypes; private final DebugInfoMode debugInfoMode; - private final boolean doLivenessAnalysis; + private final boolean clearNonLiveLocals; private boolean useProfiling; private final Plugins plugins; @@ -161,13 +162,14 @@ Full, } - protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis, - Plugins plugins) { + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, + boolean clearNonLiveLocals, Plugins plugins) { this.eagerResolving = eagerResolving; this.omitAllExceptionEdges = omitAllExceptionEdges; + this.omitAssertions = omitAssertions; this.debugInfoMode = debugInfoMode; this.skippedExceptionTypes = skippedExceptionTypes; - this.doLivenessAnalysis = doLivenessAnalysis; + this.clearNonLiveLocals = clearNonLiveLocals; this.useProfiling = true; this.plugins = plugins; } @@ -179,7 +181,7 @@ */ public GraphBuilderConfiguration copy() { Plugins newPlugins = new Plugins(plugins); - GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins); + GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins); result.useProfiling = useProfiling; return result; } @@ -193,20 +195,24 @@ } public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins); } public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) { - return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins); + } + + public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) { + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins); } public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins); } - public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, plugins); + public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) { + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins); } public ResolvedJavaType[] getSkippedExceptionTypes() { @@ -221,6 +227,10 @@ return omitAllExceptionEdges; } + public boolean omitAssertions() { + return omitAssertions; + } + public boolean insertNonSafepointDebugInfo() { return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal(); } @@ -229,32 +239,36 @@ return debugInfoMode.ordinal() >= DebugInfoMode.Full.ordinal(); } - public boolean doLivenessAnalysis() { - return doLivenessAnalysis; + public boolean insertSimpleDebugInfo() { + return debugInfoMode == DebugInfoMode.Simple; + } + + public boolean clearNonLiveLocals() { + return clearNonLiveLocals; } public static GraphBuilderConfiguration getDefault(Plugins plugins) { - return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Thu May 28 17:44:05 2015 +0200 @@ -36,43 +36,12 @@ import com.oracle.graal.nodes.type.*; /** - * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object. + * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a + * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} . */ public interface GraphBuilderContext { /** - * Information about a snippet or method substitution currently being processed by the graph - * builder. When in the scope of a replacement, the graph builder does not check the value kinds - * flowing through the JVM state since replacements can employ non-Java kinds to represent - * values such as raw machine words and pointers. - */ - public interface Replacement { - - /** - * Gets the method being replaced. - */ - ResolvedJavaMethod getOriginalMethod(); - - /** - * Gets the replacement method. - */ - ResolvedJavaMethod getReplacementMethod(); - - /** - * Determines if this replacement is being inlined as a compiler intrinsic. A compiler - * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler - * intrinsic will restart the interpreter at the intrinsified call. - */ - boolean isIntrinsic(); - - /** - * Determines if a call within the compilation scope of this replacement represents a call - * to the {@linkplain #getOriginalMethod() original} method. - */ - boolean isCallToOriginal(ResolvedJavaMethod method); - } - - /** * Raw operation for adding a node to the graph when neither {@link #add}, * {@link #addPush(ValueNode)} nor {@link #addPush(Kind, ValueNode)} can be used. * @@ -115,8 +84,8 @@ T equivalentValue = append(value); if (equivalentValue instanceof StateSplit) { StateSplit stateSplit = (StateSplit) equivalentValue; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(createStateAfter()); + if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { + setStateAfter(stateSplit); } } return equivalentValue; @@ -149,8 +118,8 @@ push(kind.getStackKind(), equivalentValue); if (equivalentValue instanceof StateSplit) { StateSplit stateSplit = (StateSplit) equivalentValue; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(createStateAfter()); + if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { + setStateAfter(stateSplit); } } return equivalentValue; @@ -194,9 +163,12 @@ /** * Creates a snap shot of the current frame state with the BCI of the instruction after the one - * currently being parsed. + * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side + * effect} node. + * + * @param sideEffect a side effect node just appended to the graph */ - FrameState createStateAfter(); + void setStateAfter(StateSplit sideEffect); /** * Gets the parsing context for the method that inlines the method being parsed by this context. @@ -204,7 +176,19 @@ GraphBuilderContext getParent(); /** - * Gets the method currently being parsed. + * Gets the first ancestor parsing context that is not parsing a + * {@linkplain #parsingIntrinsic() intrinsic}. + */ + default GraphBuilderContext getNonIntrinsicAncestor() { + GraphBuilderContext ancestor = getParent(); + while (ancestor != null && ancestor.parsingIntrinsic()) { + ancestor = ancestor.getParent(); + } + return ancestor; + } + + /** + * Gets the method being parsed by this context. */ ResolvedJavaMethod getMethod(); @@ -223,9 +207,18 @@ */ JavaType getInvokeReturnType(); + default Stamp getInvokeReturnStamp() { + JavaType returnType = getInvokeReturnType(); + if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) { + return StampFactory.declared((ResolvedJavaType) returnType); + } else { + return StampFactory.forKind(returnType.getKind()); + } + } + /** - * Gets the inline depth of this context. 0 implies this is the context for the compilation root - * method. + * Gets the inline depth of this context. A return value of 0 implies that this is the context + * for the parse root. */ default int getDepth() { GraphBuilderContext parent = getParent(); @@ -233,17 +226,18 @@ } /** - * Determines if the current parsing context is a snippet or method substitution. + * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined + * by an intrinsic. */ - default boolean parsingReplacement() { - return getReplacement() != null; + default boolean parsingIntrinsic() { + return getIntrinsic() != null; } /** - * Gets the replacement of the current parsing context or {@code null} if not - * {@link #parsingReplacement() parsing a replacement}. + * Gets the intrinsic of the current parsing context or {@code null} if not + * {@link #parsingIntrinsic() parsing an intrinsic}. */ - Replacement getReplacement(); + IntrinsicContext getIntrinsic(); BailoutException bailout(String string); @@ -268,5 +262,4 @@ } return value; } - } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InlineInvokePlugin.java Thu May 28 17:44:05 2015 +0200 @@ -26,8 +26,9 @@ import com.oracle.graal.nodes.*; /** - * Plugin for specifying what is inlined during graph parsing or for post-processing non-inlined - * invocations that result in {@link Invoke} nodes. + * Plugin for specifying what is inlined during graph parsing. This plugin is also + * {@linkplain #notifyOfNoninlinedInvoke notified} of non-inlined invocations (i.e., those for which + * an {@link Invoke} node is created). */ public interface InlineInvokePlugin extends GraphBuilderPlugin { @@ -39,24 +40,14 @@ public final ResolvedJavaMethod methodToInline; /** - * Specifies if {@link #methodToInline} is to be considered a - * {@linkplain GraphBuilderContext.Replacement replacement} for the {@code method} passed to - * {@link InlineInvokePlugin#getInlineInfo}. - */ - public final boolean isReplacement; - - /** - * Specifies if {@link #methodToInline} is an intrinsic for the original method. If so, any - * {@link StateSplit} node created in the (recursive) inlining scope will be given a frame - * state that restarts the interpreter just before the intrinsified invocation. + * Specifies if {@link #methodToInline} is an intrinsic for the original method (i.e., the + * {@code method} passed to {@link InlineInvokePlugin#getInlineInfo}). */ public final boolean isIntrinsic; - public InlineInfo(ResolvedJavaMethod methodToInline, boolean isReplacement, boolean isIntrinsic) { + public InlineInfo(ResolvedJavaMethod methodToInline, boolean isIntrinsic) { this.methodToInline = methodToInline; this.isIntrinsic = isIntrinsic; - this.isReplacement = isReplacement; - assert !isIntrinsic || isReplacement : "cannot be an intrinsic without also being a replacement"; } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/IntrinsicContext.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015, 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.graphbuilderconf; + +import static com.oracle.graal.api.code.BytecodeFrame.*; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; + +/** + * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of + * snippets) that is itself implemented in Java. This interface provides information about the + * intrinsic currently being processed by the graph builder. + * + * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing + * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw + * machine words and pointers. + */ +public class IntrinsicContext { + + /** + * Gets the method being intrinsified. + */ + final ResolvedJavaMethod method; + + /** + * Gets the method providing the intrinsic implementation. + */ + final ResolvedJavaMethod intrinsic; + + public ResolvedJavaMethod getOriginalMethod() { + return method; + } + + public ResolvedJavaMethod getIntrinsicMethod() { + return intrinsic; + } + + /** + * Determines if a call within the compilation scope of this intrinsic represents a call to the + * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial + * intrinsification falls back to the original method. + */ + public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) { + return method.equals(targetMethod) || intrinsic.equals(targetMethod); + } + + final CompilationContext compilationContext; + + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, CompilationContext compilationContext) { + this.method = method; + this.intrinsic = intrinsic; + this.compilationContext = compilationContext; + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)"); + } + + public boolean isPostParseInlined() { + return compilationContext.equals(INLINE_AFTER_PARSING); + } + + public boolean isCompilationRoot() { + return compilationContext.equals(ROOT_COMPILATION); + } + + /** + * Denotes the compilation context in which an intrinsic is being parsed. + */ + public enum CompilationContext { + /** + * An intrinsic is being processed when parsing an invoke bytecode that calls the + * intrinsified method. + */ + INLINE_DURING_PARSING, + + /** + * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph. + */ + INLINE_AFTER_PARSING, + + /** + * An intrinsic is the root of compilation. + */ + ROOT_COMPILATION + } + + /** + * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that + * are control flow predecessors of the current point in a graph. + */ + public interface SideEffectsState { + + /** + * Determines if the current program point is preceded by one or more side effects. + */ + boolean isAfterSideEffect(); + + /** + * Gets the side effects preceding the current program point. + */ + Iterable sideEffects(); + + /** + * Records a side effect for the current program point. + */ + void addSideEffect(StateSplit sideEffect); + } + + public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit) { + assert forStateSplit != graph.start(); + if (forStateSplit.hasSideEffect()) { + if (sideEffects.isAfterSideEffect()) { + // Only the last side effect on any execution path in a replacement + // can inherit the stateAfter of the replaced node + FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI)); + for (StateSplit lastSideEffect : sideEffects.sideEffects()) { + lastSideEffect.setStateAfter(invalid); + } + } + sideEffects.addSideEffect(forStateSplit); + return graph.add(new FrameState(AFTER_BCI)); + } else { + if (forStateSplit instanceof AbstractMergeNode) { + // Merge nodes always need a frame state + if (sideEffects.isAfterSideEffect()) { + // A merge after one or more side effects + return graph.add(new FrameState(AFTER_BCI)); + } else { + // A merge before any side effects + return graph.add(new FrameState(BEFORE_BCI)); + } + } else { + // Other non-side-effects do not need a state + return null; + } + } + } + + @Override + public String toString() { + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}"; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Thu May 28 17:44:05 2015 +0200 @@ -227,6 +227,14 @@ } /** + * Disallows new registrations of new plugins, and creates the internal tables for method + * lookup. + */ + public void closeRegistration() { + plugins.createEntries(); + } + + /** * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} * before searching in this object. */ diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -40,7 +40,7 @@ JavaConstant result = constantReflection.readConstantFieldValue(field, receiver); if (result != null) { ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess); - b.addPush(constantNode.getKind().getStackKind(), constantNode); + b.addPush(field.getKind(), constantNode); return true; } return false; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java Thu May 28 17:44:05 2015 +0200 @@ -62,7 +62,7 @@ idVerifierMap.put(holder, id); } } else { - assert idVerifierMap.get(holder) == id; + assert !idVerifierMap.containsKey(holder) || idVerifierMap.get(holder) == id; } return id; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java Thu May 28 17:44:05 2015 +0200 @@ -199,38 +199,7 @@ public V get(MethodIdHolder method) { if (entries == null) { - // 'assignIds' synchronizes on a global lock which ensures thread safe - // allocation of identifiers across all MethodIdHolder objects - MethodIdHolder.assignIds(new Consumer() { - - public void accept(MethodIdAllocator idAllocator) { - if (entries == null) { - if (registrations.isEmpty()) { - entries = allocateEntries(0); - } else { - int max = Integer.MIN_VALUE; - for (MethodKey methodKey : registrations) { - MethodIdHolder m = methodKey.resolve(metaAccess); - int id = idAllocator.assignId(m); - if (id < minId) { - minId = id; - } - if (id > max) { - max = id; - } - methodKey.id = id; - } - - int length = (max - minId) + 1; - entries = allocateEntries(length); - for (MethodKey m : registrations) { - int index = m.id - minId; - entries[index] = m.value; - } - } - } - } - }); + createEntries(); } int id = method.getMethodId(); @@ -238,6 +207,41 @@ return index >= 0 && index < entries.length ? entries[index] : null; } + public void createEntries() { + // 'assignIds' synchronizes on a global lock which ensures thread safe + // allocation of identifiers across all MethodIdHolder objects + MethodIdHolder.assignIds(new Consumer() { + + public void accept(MethodIdAllocator idAllocator) { + if (entries == null) { + if (registrations.isEmpty()) { + entries = allocateEntries(0); + } else { + int max = Integer.MIN_VALUE; + for (MethodKey methodKey : registrations) { + MethodIdHolder m = methodKey.resolve(metaAccess); + int id = idAllocator.assignId(m); + if (id < minId) { + minId = id; + } + if (id > max) { + max = id; + } + methodKey.id = id; + } + + int length = (max - minId) + 1; + entries = allocateEntries(length); + for (MethodKey m : registrations) { + int index = m.id - minId; + entries[index] = m.value; + } + } + } + } + }); + } + @Override public String toString() { return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", ")); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu May 28 17:44:05 2015 +0200 @@ -36,10 +36,10 @@ import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; @@ -251,7 +251,7 @@ emitCodeBody(installedCodeOwner, crb, lir); // Emit the suffix - emitCodeSuffix(installedCodeOwner, crb, asm, frameMap); + emitCodeSuffix(installedCodeOwner, crb, asm, config, frameMap); // Profile assembler instructions profileInstructions(lir, crb); @@ -265,7 +265,7 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedEntry) { HotSpotProviders providers = getProviders(); if (installedCodeOwner != null && !installedCodeOwner.isStatic()) { - MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY); + crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false); Register inlineCacheKlass = rax; // see definition of IC_Klass in // c1_LIRAssembler_x86.cpp @@ -287,9 +287,9 @@ } asm.align(config.codeEntryAlignment); - MarkId.recordMark(crb, MarkId.OSR_ENTRY); + crb.recordMark(config.MARKID_OSR_ENTRY); asm.bind(verifiedEntry); - MarkId.recordMark(crb, MarkId.VERIFIED_ENTRY); + crb.recordMark(config.MARKID_VERIFIED_ENTRY); } /** @@ -303,15 +303,16 @@ /** * @param installedCodeOwner see {@link Backend#emitCode} + * @param config */ - public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) { + public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, AMD64MacroAssembler asm, HotSpotVMConfig config, FrameMap frameMap) { HotSpotProviders providers = getProviders(); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; if (!frameContext.isStub) { HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); - MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY); + crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null); - MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY); + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since @@ -324,4 +325,10 @@ } } + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new AMD64HotSpotRegisterAllocationConfig(registerConfigNonNull); + } + } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Thu May 28 17:44:05 2015 +0200 @@ -223,7 +223,7 @@ } protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { - return new HotSpotCodeCacheProvider(runtime, target, regConfig); + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); } protected HotSpotMetaAccessProvider createMetaAccess(HotSpotGraalRuntimeProvider runtime) { @@ -269,15 +269,15 @@ } else { /* * System V Application Binary Interface, AMD64 Architecture Processor Supplement - * + * * Draft Version 0.96 - * + * * http://www.uclibc.org/docs/psABI-x86_64.pdf - * + * * 3.2.1 - * + * * ... - * + * * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12 * through %r15 "belong" to the calling function and the called function is required to * preserve their values. In other words, a called function must preserve these diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java Thu May 28 17:44:05 2015 +0200 @@ -25,20 +25,22 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; -import com.oracle.graal.hotspot.HotSpotGraalRuntime; public final class AMD64HotSpotCardTableAddressOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableAddressOp.class); @Def({OperandFlag.REG}) private AllocatableValue result; - public AMD64HotSpotCardTableAddressOp(AllocatableValue result) { + private final HotSpotVMConfig config; + + public AMD64HotSpotCardTableAddressOp(AllocatableValue result, HotSpotVMConfig config) { super(TYPE); this.result = result; + this.config = config; } @Override @@ -48,7 +50,7 @@ JavaConstant address = JavaConstant.forIntegerKind(hostWordKind, 0); // recordDataReferenceInCode forces the mov to be rip-relative asm.movq(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(address, alignment)); - MarkId.recordMark(crb, MarkId.CARD_TABLE_ADDRESS); + crb.recordMark(config.MARKID_CARD_TABLE_ADDRESS); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java Thu May 28 17:44:05 2015 +0200 @@ -25,20 +25,22 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; -import com.oracle.graal.hotspot.HotSpotGraalRuntime; public final class AMD64HotSpotCardTableShiftOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableShiftOp.class); @Def({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue result; - public AMD64HotSpotCardTableShiftOp(AllocatableValue result) { + private final HotSpotVMConfig config; + + public AMD64HotSpotCardTableShiftOp(AllocatableValue result, HotSpotVMConfig config) { super(TYPE); this.result = result; + this.config = config; } @Override @@ -48,6 +50,6 @@ JavaConstant shift = JavaConstant.forIntegerKind(hostWordKind, 0); // recordDataReferenceInCode forces the mov to be rip-relative asm.movq(ValueUtil.asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(shift, alignment)); - MarkId.recordMark(crb, MarkId.CARD_TABLE_SHIFT); + crb.recordMark(config.MARKID_CARD_TABLE_SHIFT); } } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu May 28 17:44:05 2015 +0200 @@ -23,7 +23,6 @@ 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.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; @@ -34,13 +33,10 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.*; @@ -52,8 +48,6 @@ import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; -import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.asm.*; @@ -261,14 +255,14 @@ @Override public Value emitCardTableShift() { Variable result = newVariable(LIRKind.value(Kind.Long)); - append(new AMD64HotSpotCardTableShiftOp(result)); + append(new AMD64HotSpotCardTableShiftOp(result, config)); return result; } @Override public Value emitCardTableAddress() { Variable result = newVariable(LIRKind.value(Kind.Long)); - append(new AMD64HotSpotCardTableAddressOp(result)); + append(new AMD64HotSpotCardTableAddressOp(result, config)); return result; } @@ -494,15 +488,6 @@ } } - private static LIRKind toStackKind(LIRKind kind) { - if (kind.getPlatformKind() instanceof Kind) { - Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind(); - return kind.changeType(stackKind); - } else { - return kind; - } - } - public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { Variable frameSizeVariable = load(frameSize); Variable framePcVariable = load(framePc); @@ -512,47 +497,8 @@ } @Override - public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { - AMD64AddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(toStackKind(kind)); - switch ((Kind) kind.getPlatformKind()) { - case Boolean: - append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); - break; - case Byte: - append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); - break; - case Char: - append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); - break; - case Short: - append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); - break; - case Int: - append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); - break; - case Long: - case Object: - append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); - break; - case Float: - append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); - break; - case Double: - append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - return result; - } - - private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { - if (value.isNull()) { - assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; - OperandSize size = kind == Kind.Int ? DWORD : QWORD; - append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); - } else if (value instanceof HotSpotConstant) { + protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { + if (value instanceof HotSpotConstant && value.isNonNull()) { HotSpotConstant c = (HotSpotConstant) value; if (c.isCompressed()) { assert kind == Kind.Int; @@ -565,86 +511,7 @@ emitStore(kind, address, asAllocatable(value), state); } } else { - AMD64MIOp op = AMD64MIOp.MOV; - OperandSize size; - long imm; - - switch (kind) { - case Boolean: - case Byte: - op = AMD64MIOp.MOVB; - size = BYTE; - imm = value.asInt(); - break; - case Char: - case Short: - size = WORD; - imm = value.asInt(); - break; - case Int: - size = DWORD; - imm = value.asInt(); - break; - case Long: - size = QWORD; - imm = value.asLong(); - break; - case Float: - size = DWORD; - imm = Float.floatToRawIntBits(value.asFloat()); - break; - case Double: - size = QWORD; - imm = Double.doubleToRawLongBits(value.asDouble()); - break; - default: - throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind); - } - - if (NumUtil.isInt(imm)) { - append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); - } else { - emitStore(kind, address, asAllocatable(value), state); - } - } - } - - private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { - switch (kind) { - case Boolean: - case Byte: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); - break; - case Char: - case Short: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); - break; - case Int: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); - break; - case Long: - case Object: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); - break; - case Float: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); - break; - case Double: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { - AMD64AddressValue storeAddress = asAddressValue(address); - Kind kind = (Kind) lirKind.getPlatformKind(); - if (isConstant(input)) { - emitStoreConst(kind, storeAddress, asConstant(input), state); - } else { - emitStore(kind, storeAddress, asAllocatable(input), state); + super.emitStoreConst(kind, address, value, state); } } @@ -699,40 +566,7 @@ } } - public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { - LIRKind kind = newValue.getLIRKind(); - assert kind.equals(expectedValue.getLIRKind()); - Kind memKind = (Kind) kind.getPlatformKind(); - - AMD64AddressValue addressValue = asAddressValue(address); - RegisterValue raxRes = AMD64.rax.asValue(kind); - emitMove(raxRes, expectedValue); - append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); - - assert trueValue.getLIRKind().equals(falseValue.getLIRKind()); - Variable result = newVariable(trueValue.getLIRKind()); - append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); - return result; - } - - public Value emitAtomicReadAndAdd(Value address, Value delta) { - LIRKind kind = delta.getLIRKind(); - Kind memKind = (Kind) kind.getPlatformKind(); - Variable result = newVariable(kind); - AMD64AddressValue addressValue = asAddressValue(address); - append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta))); - return result; - } - - public Value emitAtomicReadAndWrite(Value address, Value newValue) { - LIRKind kind = newValue.getLIRKind(); - Kind memKind = (Kind) kind.getPlatformKind(); - Variable result = newVariable(kind); - AMD64AddressValue addressValue = asAddressValue(address); - append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); - return result; - } - + @Override public void emitNullCheck(Value address, LIRFrameState state) { if (address.getLIRKind().getPlatformKind() == Kind.Int) { CompressEncoding encoding = config.getOopEncoding(); @@ -744,8 +578,7 @@ } append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state)); } else { - assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!"; - append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); + super.emitNullCheck(address, state); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -53,6 +53,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; /** * LIR generator specialized for AMD64 HotSpot. @@ -158,7 +159,7 @@ assert invokeKind.isDirect(); HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; - append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind)); + append(new AMD64HotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig())); } } @@ -171,7 +172,7 @@ AllocatableValue targetAddressDst = AMD64.rax.asValue(targetAddressSrc.getLIRKind()); gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc); gen.emitMove(targetAddressDst, targetAddressSrc); - append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState)); + append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, runtime.getConfig())); } else { super.emitIndirectCall(callTarget, result, parameters, temps, callState); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 2015, 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 java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.common.alloc.*; + +class AMD64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig { + /** + * Specify priority of register selection within phases of register allocation. Highest priority + * is first. A useful heuristic is to give registers a low priority when they are required by + * machine instructions, like EAX and EDX on I486, and choose no-save registers before + * save-on-call, & save-on-call before save-on-entry. Registers which participate in fixed + * calling sequences should come last. Registers which are used as pairs must fall on an even + * boundary. + * + * Adopted from x86_64.ad. + */ + // @formatter:off + static final Register[] registerAllocationOrder = { + r10, r11, r8, r9, r12, rcx, rbx, rdi, rdx, rsi, rax, rbp, r13, r14, /*r15,*/ /*rsp,*/ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + // @formatter:on + + public AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) { + super(registerConfig); + } + + @Override + protected Register[] initAllocatable(Register[] registers) { + BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().length); + Register[] regs = super.initAllocatable(registers); + for (Register reg : regs) { + regMap.set(reg.number); + } + + Register[] allocatableRegisters = new Register[regs.length]; + int i = 0; + for (Register reg : registerAllocationOrder) { + if (regMap.get(reg.number)) { + allocatableRegisters[i++] = reg; + } + } + + assert i == allocatableRegisters.length; + return allocatableRegisters; + } + + @Override + protected AllocatableRegisters createAllocatableRegisters(Register[] registers) { + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (Register reg : registers) { + int number = reg.number; + if (number < min) { + min = number; + } + if (number > max) { + max = number; + } + } + assert min < max; + return new AllocatableRegisters(registers, min, max); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; @@ -84,21 +83,21 @@ // co-located with the immutable code. asm.movq(scratch, (AMD64Address) crb.recordDataReferenceInCode(pollingPageAddress, alignment)); final int pos = asm.position(); - MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); } asm.testl(rax, new AMD64Address(scratch)); } else if (isPollingPageFar(config)) { asm.movq(scratch, config.safepointPollingAddress); - MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); final int pos = asm.position(); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); } asm.testl(rax, new AMD64Address(scratch)); } else { - MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_NEAR : MarkId.POLL_NEAR); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR); final int pos = asm.position(); if (state != null) { crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -24,7 +24,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; import com.oracle.graal.lir.asm.*; @@ -39,16 +39,18 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotspotDirectStaticCallOp.class); private final InvokeKind invokeKind; + private final HotSpotVMConfig config; - AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) { + AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) { super(TYPE, target, result, parameters, temps, state); assert invokeKind.isDirect(); this.invokeKind = invokeKind; + this.config = config; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - MarkId.recordMark(crb, invokeKind == InvokeKind.Static ? MarkId.INVOKESTATIC : MarkId.INVOKESPECIAL); + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); super.emitCode(crb, masm); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -26,9 +26,8 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.AMD64Call.*; +import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; @@ -54,7 +53,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { // The mark for an invocation that uses an inline cache must be placed at the // instruction that loads the Klass from the inline cache. - MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE); + crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); // This must be emitted exactly like this to ensure it's patchable masm.movq(AMD64.rax, config.nonOopBits); super.emitCode(crb, masm); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp; @@ -52,14 +52,17 @@ @Use({REG}) protected Value metaspaceMethod; - AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { + private final HotSpotVMConfig config; + + AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, HotSpotVMConfig config) { super(TYPE, targetMethod, result, parameters, temps, targetAddress, state); this.metaspaceMethod = metaspaceMethod; + this.config = config; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - MarkId.recordMark(crb, MarkId.INLINE_INVOKE); + crb.recordMark(config.MARKID_INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert !callReg.equals(METHOD); AMD64Call.indirectCall(crb, masm, callReg, callTarget, state); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/overview.html --- a/graal/com.oracle.graal.hotspot.server/overview.html Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ - - - - - - - - -Documentation for the com.oracle.graal.hotspot.server project. - - - diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.server; - -import java.io.*; -import java.net.*; -import java.util.*; - -import javax.net.*; - -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.logging.*; - -/** - * Server side of the client/server compilation model. The server listens for connections on the - * hardcoded port 1199. - */ -public class CompilationServer implements Runnable { - - public static void main(String[] args) throws Exception { - new CompilationServer(false).run(); - } - - public interface ConnectionObserver { - - void connectionStarted(HotSpotGraalRuntimeProvider compiler); - - void connectionFinished(HotSpotGraalRuntimeProvider compiler); - } - - private final boolean multiple; - private final ArrayList observers = new ArrayList<>(); - - /** - * Creates a new Compilation server. The server is activated by calling {@link #run()} directly - * or via a new {@link Thread}. - * - * @param multiple true if the server should server should serve an infinite amount of - * consecutive connections, false if it should terminate after the first connection - * ends. - */ - public CompilationServer(boolean multiple) { - this.multiple = multiple; - } - - public void addConnectionObserver(ConnectionObserver observer) { - observers.add(observer); - } - - public void removeConnectionObserver(ConnectionObserver observer) { - observers.remove(observer); - } - - public void run() { - final ServerSocket serverSocket; - try { - serverSocket = ServerSocketFactory.getDefault().createServerSocket(1199); - } catch (IOException e) { - throw new RuntimeException("Couldn't create compilation server", e); - } - do { - Socket socket = null; - try { - Logger.log("Compilation server ready, waiting for client to connect..."); - socket = serverSocket.accept(); - Logger.log("Connected to " + socket.getRemoteSocketAddress()); - - ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream()); - - // get the CompilerToVM proxy from the client - CompilerToVM toVM = (CompilerToVM) streams.getInvocation().waitForResult(false); - - // return the initialized compiler to the client - HotSpotGraalRuntimeProvider compiler = initializeServer(toVM); - streams.getInvocation().sendResult(compiler); - - for (ConnectionObserver observer : observers) { - observer.connectionStarted(compiler); - } - - streams.getInvocation().waitForResult(true); - - for (ConnectionObserver observer : observers) { - observer.connectionFinished(compiler); - } - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } finally { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - } - } - } - } while (multiple); - } - - @SuppressWarnings("unused") - private static HotSpotGraalRuntimeProvider initializeServer(CompilerToVM toVM) { - // TODO(thomaswue): Fix creation of compiler instances on server side. - return null; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.server; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.hotspot.logging.*; - -/** - * A collection of java.lang.reflect proxies that communicate over a socket connection. - * - * Calling a method sends the method name and the parameters through the socket. Afterwards this - * class waits for a result. While waiting for a result three types of objects can arrive through - * the socket: a method invocation, a method result or an exception. Method invocation can thus be - * recursive. - */ -public class InvocationSocket { - - private static final boolean DEBUG = false; - private static final boolean COUNT_CALLS = false; - - private static final HashSet cachedMethodNames = new HashSet<>(); - private static final HashSet forbiddenMethodNames = new HashSet<>(); - - static { - cachedMethodNames.add("name"); - cachedMethodNames.add("kind"); - cachedMethodNames.add("isResolved"); - cachedMethodNames.add("getCompilerToVM"); - cachedMethodNames.add("exactType"); - cachedMethodNames.add("isInitialized"); - forbiddenMethodNames.add("javaClass"); - } - - private final ObjectOutputStream output; - private final ObjectInputStream input; - - private final Map counts = new HashMap<>(); - - public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) { - this.output = output; - this.input = input; - - if (COUNT_CALLS) { - Runtime.getRuntime().addShutdownHook(new Thread() { - - @Override - public void run() { - SortedMap sorted = new TreeMap<>(); - for (Map.Entry entry : counts.entrySet()) { - sorted.put(entry.getValue(), entry.getKey()); - } - for (Map.Entry entry : sorted.entrySet()) { - TTY.println(entry.getKey() + ": " + entry.getValue()); - } - } - }); - } - } - - /** - * Represents one invocation of a method that is transferred via the socket connection. - * - */ - private static class Invocation implements Serializable { - - private static final long serialVersionUID = -799162779226626066L; - - public Object receiver; - public String methodName; - public Object[] args; - - public Invocation(Object receiver, String methodName, Object[] args) { - this.receiver = receiver; - this.methodName = methodName; - this.args = args; - } - } - - /** - * Represents the result of an invocation that is transferred via the socket connection. - * - */ - private static class Result implements Serializable { - - private static final long serialVersionUID = -7496058356272415814L; - - public Object result; - - public Result(Object result) { - this.result = result; - } - } - - private void incCount(String name, Object[] args) { - if (COUNT_CALLS) { - String nameAndArgCount = name + (args == null ? 0 : args.length); - if (counts.get(nameAndArgCount) != null) { - counts.put(nameAndArgCount, counts.get(nameAndArgCount) + 1); - } else { - counts.put(nameAndArgCount, 1); - } - } - } - - /** - * Each instance of this class handles remote invocations for one instance of a Remote class. It - * will forward all interface methods to the other end of the socket and cache the results of - * calls to certain methods. - * - */ - public class Handler implements InvocationHandler { - - private final Object receiver; - private final HashMap cache = new HashMap<>(); - - public Handler(Object receiver) { - this.receiver = receiver; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // only interface methods can be transferred, java.lang.Object methods - if (method.getDeclaringClass() == Object.class) { - return method.invoke(receiver, args); - } - String methodName = method.getName(); - // check if the result of this zero-arg method was cached - if (args == null || args.length == 0) { - if (cache.containsKey(methodName)) { - return cache.get(methodName); - } - } - if (forbiddenMethodNames.contains(methodName)) { - throw new IllegalAccessException(methodName + " not allowed"); - } - Object result = null; - try { - if (DEBUG) { - Logger.startScope("invoking remote " + methodName); - } - incCount(methodName, args); - - output.writeObject(new Invocation(receiver, methodName, args)); - output.flush(); - result = waitForResult(false); - - // result caching for selected methods - if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) { - cache.put(methodName, result); - } - return result; - } catch (Throwable t) { - t.printStackTrace(); - throw t; - } finally { - if (DEBUG) { - Logger.endScope(" = " + result); - } - } - } - } - - /** - * Waits for the result of a remote method invocation. Invocations that should be executed in - * this VM might arrive while waiting for the result, and these invocations will be executed - * before again waiting fort he result. - */ - @SuppressWarnings("unused") - public Object waitForResult(boolean eofExpected) throws IOException, ClassNotFoundException { - while (true) { - Object in; - try { - in = input.readObject(); - } catch (EOFException e) { - if (eofExpected) { - return null; - } - throw e; - } - if (in instanceof Result) { - return ((Result) in).result; - } else if (in instanceof RuntimeException) { - throw (RuntimeException) in; - } else if (in instanceof Throwable) { - throw new RuntimeException((Throwable) in); - } - - Invocation invoke = (Invocation) in; - Method method = null; - for (Class clazz = invoke.receiver.getClass(); clazz != null; clazz = clazz.getSuperclass()) { - for (Method m : clazz.getDeclaredMethods()) { - if (invoke.methodName.equals(m.getName())) { - method = m; - break; - } - } - } - if (method == null) { - Exception e = new UnsupportedOperationException("unknown method " + invoke.methodName); - e.printStackTrace(); - output.writeObject(e); - output.flush(); - } else { - Object result = null; - try { - if (invoke.args == null) { - if (DEBUG) { - Logger.startScope("invoking local " + invoke.methodName); - } - result = method.invoke(invoke.receiver); - } else { - if (Logger.ENABLED && DEBUG) { - StringBuilder str = new StringBuilder(); - str.append("invoking local " + invoke.methodName + "("); - for (int i = 0; i < invoke.args.length; i++) { - str.append(i == 0 ? "" : ", "); - str.append(Logger.pretty(invoke.args[i])); - } - str.append(")"); - Logger.startScope(str.toString()); - } - result = method.invoke(invoke.receiver, invoke.args); - } - result = new Result(result); - } catch (IllegalArgumentException e) { - TTY.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } catch (InvocationTargetException e) { - TTY.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } catch (IllegalAccessException e) { - TTY.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } finally { - if (DEBUG) { - if (result instanceof Result) { - Logger.endScope(" = " + ((Result) result).result); - } else { - Logger.endScope(" = " + result); - } - } - } - output.writeObject(result); - output.flush(); - } - } - } - - /** - * Sends a result without invoking a method, used by CompilationServer startup code. - */ - public void sendResult(Object obj) throws IOException { - output.writeObject(new Result(obj)); - output.flush(); - } - // CheckStyle: resume system..print check -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/Remote.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/Remote.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.server; - -public interface Remote { - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/ReplacingStreams.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2011, 2014, 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.server; - -import static com.oracle.graal.graph.util.CollectionsAccess.*; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.logging.*; - -public class ReplacingStreams { - - private Map objectMap = newIdentityMap(); - private ArrayList objectList = new ArrayList<>(); - - private ReplacingOutputStream output; - private ReplacingInputStream input; - - private InvocationSocket invocation; - - public ReplacingStreams(OutputStream outputStream, InputStream inputStream) throws IOException { - output = new ReplacingOutputStream(new BufferedOutputStream(outputStream)); - // required, because creating an ObjectOutputStream writes a header, but doesn't flush the - // stream - output.flush(); - input = new ReplacingInputStream(new BufferedInputStream(inputStream)); - invocation = new InvocationSocket(output, input); - - addStaticObject(Value.ILLEGAL); - } - - public void setInvocationSocket(InvocationSocket invocation) { - this.invocation = invocation; - } - - public ReplacingOutputStream getOutput() { - return output; - } - - public ReplacingInputStream getInput() { - return input; - } - - public InvocationSocket getInvocation() { - return invocation; - } - - private void addStaticObject(Object obj) { - int id = objectList.size(); - objectList.add(obj); - objectMap.put(obj, new Placeholder(id)); - } - - public static class Placeholder implements Serializable { - - private static final long serialVersionUID = 6071894297788156945L; - public final int id; - - public Placeholder(int id) { - this.id = id; - } - - @Override - public String toString() { - return "#<" + id + ">"; - } - } - - public static class NewRemoteCallPlaceholder implements Serializable { - - private static final long serialVersionUID = 3084101671389500206L; - public final Class[] interfaces; - - public NewRemoteCallPlaceholder(Class[] interfaces) { - this.interfaces = interfaces; - } - } - - public static class NewDummyPlaceholder implements Serializable { - - private static final long serialVersionUID = 2692666726573532288L; - } - - /** - * Replaces certain cir objects that cannot easily be made Serializable. - */ - public class ReplacingInputStream extends ObjectInputStream { - - public ReplacingInputStream(InputStream in) throws IOException { - super(in); - enableResolveObject(true); - } - - @Override - protected Object resolveObject(Object obj) throws IOException { - // see ReplacingInputStream.replaceObject for details on when these types of objects are - // created - - if (obj instanceof Placeholder) { - Placeholder placeholder = (Placeholder) obj; - Object resolvedObj = objectList.get(placeholder.id); - return resolvedObj; - } - - if (obj instanceof NewRemoteCallPlaceholder) { - NewRemoteCallPlaceholder newPlaceholder = (NewRemoteCallPlaceholder) obj; - Placeholder placeholder = new Placeholder(objectList.size()); - Object resolvedObj = Proxy.newProxyInstance(getClass().getClassLoader(), newPlaceholder.interfaces, invocation.new Handler(placeholder)); - objectMap.put(resolvedObj, placeholder); - objectList.add(resolvedObj); - return resolvedObj; - } - - if (obj instanceof NewDummyPlaceholder) { - Object resolvedObj = new Placeholder(objectList.size()); - objectMap.put(resolvedObj, (Placeholder) resolvedObj); - objectList.add(resolvedObj); - return resolvedObj; - } - - return obj; - } - } - - /** - * Replaces certain objects that cannot easily be made Serializable. - */ - public class ReplacingOutputStream extends ObjectOutputStream { - - public ReplacingOutputStream(OutputStream out) throws IOException { - super(out); - enableReplaceObject(true); - } - - @Override - protected Object replaceObject(Object obj) throws IOException { - // is the object a known instance? - Placeholder placeholder = objectMap.get(obj); - if (placeholder != null) { - return placeholder; - } - - // is the object an instance of a class that will always be executed remotely? - if (obj instanceof Remote) { - return createRemoteCallPlaceholder(obj); - } - - // Remote object constants must implement Remote - assert !(obj instanceof JavaConstant) || ((JavaConstant) obj).getKind() != Kind.Object; - - return obj; - } - } - - private Object createRemoteCallPlaceholder(Object obj) { - // collect all interfaces that this object's class implements (proxies only support - // interfaces) - objectMap.put(obj, new Placeholder(objectList.size())); - objectList.add(obj); - return new NewRemoteCallPlaceholder(ProxyUtil.getAllInterfaces(obj.getClass())); - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/package-info.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/package-info.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * Implementation of a compilation server socket that delegates incoming requests to Graal. - */ -package com.oracle.graal.hotspot.server; - diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu May 28 17:44:05 2015 +0200 @@ -40,9 +40,9 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; @@ -222,7 +222,7 @@ // Emit the prefix if (unverifiedStub != null) { - MarkId.recordMark(crb, MarkId.UNVERIFIED_ENTRY); + crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); // We need to use JavaCall here because we haven't entered the frame yet. CallingConvention cc = regConfig.getCallingConvention(JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false); Register inlineCacheKlass = g5; // see MacroAssembler::ic_call @@ -240,8 +240,8 @@ } masm.align(config.codeEntryAlignment); - MarkId.recordMark(crb, MarkId.OSR_ENTRY); - MarkId.recordMark(crb, MarkId.VERIFIED_ENTRY); + crb.recordMark(config.MARKID_OSR_ENTRY); + crb.recordMark(config.MARKID_VERIFIED_ENTRY); // Emit code for the LIR crb.emit(lir); @@ -252,9 +252,9 @@ HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); if (!frameContext.isStub) { - MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY); + crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null); - MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY); + crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since @@ -378,4 +378,10 @@ return overlap; } } + + @Override + public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) { + RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; + return new RegisterAllocationConfig(registerConfigNonNull); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Thu May 28 17:44:05 2015 +0200 @@ -91,7 +91,7 @@ } protected HotSpotCodeCacheProvider createCodeCache(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { - return new HotSpotCodeCacheProvider(runtime, target, regConfig); + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); } protected SPARCHotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 2015, 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.sparc; + +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.sparc.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.sparc.*; + +/** + * Jumps to the exception handler specified by {@link #address} and leaves the current window. It + * does not modify the i7 register, as the exception handler stub expects the throwing pc in it. + *

+ * See also: + *

  • Runtime1::generate_handle_exception c1_Runtime1_sparc.cpp + *
  • SharedRuntime::generate_deopt_blob at exception_in_tls_offset (sharedRuntime_sparc.cpp) + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER") +final class SPARCHotSpotJumpToExceptionHandlerOp extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerOp.class); + + @Use(REG) AllocatableValue address; + + SPARCHotSpotJumpToExceptionHandlerOp(AllocatableValue address) { + super(TYPE); + this.address = address; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + Register addrRegister = asLongReg(address); + masm.jmp(addrRegister); + masm.restoreWindow(); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Thu May 28 17:44:05 2015 +0200 @@ -49,6 +49,7 @@ import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreOp; +import com.oracle.graal.sparc.*; public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { @@ -214,6 +215,17 @@ } @Override + public boolean canInlineConstant(JavaConstant c) { + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { + return true; + } else if (c instanceof HotSpotObjectConstant) { + return ((HotSpotObjectConstant) c).isCompressed(); + } else { + return super.canInlineConstant(c); + } + } + + @Override public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) { SPARCAddressValue storeAddress = asAddressValue(address); if (isConstant(inputVal)) { @@ -243,15 +255,85 @@ } @Override + protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) { + if (src instanceof JavaConstant) { + return new SPARCHotSpotMove.HotSpotLoadConstantOp(dst, (JavaConstant) src); + } else { + return super.createMove(dst, src); + } + } + + @Override + public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, + double trueDestinationProbability) { + Value localX = x; + Value localY = y; + if (localX instanceof HotSpotObjectConstant) { + localX = load(localX); + } + if (localY instanceof HotSpotObjectConstant) { + localY = load(localY); + } + super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); + } + + @Override + protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b) { + Value localA = a; + Value localB = b; + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localA)) { + localA = SPARC.g0.asValue(LIRKind.value(Kind.Int)); + } else if (localA instanceof HotSpotObjectConstant) { + localA = load(localA); + } + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localB)) { + localB = SPARC.g0.asValue(LIRKind.value(Kind.Int)); + } else if (localB instanceof HotSpotObjectConstant) { + localB = load(localB); + } + return super.emitCompare(cmpKind, localA, localB); + } + + @Override public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { - // TODO - throw GraalInternalError.unimplemented(); + LIRKind inputKind = pointer.getLIRKind(); + assert inputKind.getPlatformKind() == Kind.Long || inputKind.getPlatformKind() == Kind.Object; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(Kind.Int)); + append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(Kind.Int)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitMove(JavaConstant.forLong(encoding.base)); + } + append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } } @Override public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { - // TODO - throw GraalInternalError.unimplemented(); + LIRKind inputKind = pointer.getLIRKind(); + assert inputKind.getPlatformKind() == Kind.Int; + if (inputKind.isReference(0)) { + // oop + Variable result = newVariable(LIRKind.reference(Kind.Object)); + append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); + return result; + } else { + // metaspace pointer + Variable result = newVariable(LIRKind.value(Kind.Long)); + AllocatableValue base = Value.ILLEGAL; + if (encoding.base != 0) { + base = emitMove(JavaConstant.forLong(encoding.base)); + } + append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); + return result; + } } /** @@ -358,10 +440,16 @@ return result; } + @Override public void emitNullCheck(Value address, LIRFrameState state) { - PlatformKind kind = address.getLIRKind().getPlatformKind(); - assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!"; - append(new NullCheckOp(load(address), state)); + PlatformKind kind = address.getPlatformKind(); + if (kind == Kind.Int) { + CompressEncoding encoding = config.getOopEncoding(); + Value uncompressed = emitUncompress(address, encoding, false); + append(new NullCheckOp(asAddressValue(uncompressed), state)); + } else { + super.emitNullCheck(address, state); + } } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotMove.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotMove.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2013, 2015, 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.sparc; + +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.*; +import com.oracle.graal.asm.sparc.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.Annul; +import com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict; +import com.oracle.graal.asm.sparc.SPARCAssembler.CC; +import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; +import com.oracle.graal.asm.sparc.SPARCAssembler.RCondition; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.sparc.*; +import com.oracle.graal.sparc.*; + +public class SPARCHotSpotMove { + + public static final class HotSpotLoadConstantOp extends SPARCLIRInstruction implements MoveOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotLoadConstantOp.class); + + @Def({REG, STACK}) private AllocatableValue result; + private final JavaConstant input; + + public HotSpotLoadConstantOp(AllocatableValue result, JavaConstant input) { + super(TYPE); + this.result = result; + this.input = input; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + if (isStackSlot(result)) { + StackSlot ss = asStackSlot(result); + try (ScratchRegister s1 = masm.getScratchRegister()) { + Register sr1 = s1.getRegister(); + loadToRegister(crb, masm, sr1.asValue(), input); + try (ScratchRegister s2 = masm.getScratchRegister()) { + Register sr2 = s2.getRegister(); + int stackBias = HotSpotGraalRuntime.runtime().getConfig().stackBias; + int offset = crb.frameMap.offsetForStackSlot(ss); + new SPARCMacroAssembler.Setx(offset + stackBias, sr2).emit(masm); + SPARCAddress addr = new SPARCAddress(SPARC.sp, sr2); + Kind resultKind = (Kind) result.getPlatformKind(); + switch (resultKind) { + case Int: + masm.stw(sr1, addr); + break; + case Long: + case Object: + masm.stx(sr1, addr); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + } else { + loadToRegister(crb, masm, result, input); + } + } + + private static void loadToRegister(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue dest, JavaConstant constant) { + assert isRegister(dest); + if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(constant)) { + masm.mov(0, asRegister(dest)); + } else if (constant instanceof HotSpotObjectConstant) { + boolean compressed = ((HotSpotObjectConstant) constant).isCompressed(); + if (crb.target.inlineObjects) { + crb.recordInlineDataInCode(constant); + if (compressed) { + masm.sethi(0xDEADDEAD >>> 10, asRegister(dest)); + masm.add(asRegister(dest), 0xAD & 0x3F, asRegister(dest)); + } else { + new SPARCMacroAssembler.Setx(0xDEADDEADDEADDEADL, asRegister(dest), true).emit(masm); + } + } else { + GraalInternalError.unimplemented(); + } + } else if (constant instanceof HotSpotMetaspaceConstant) { + assert constant.getKind() == Kind.Int || constant.getKind() == Kind.Long; + boolean compressed = constant.getKind() == Kind.Int; + boolean isImmutable = GraalOptions.ImmutableCode.getValue(); + boolean generatePIC = GraalOptions.GeneratePIC.getValue(); + crb.recordInlineDataInCode(constant); + if (compressed) { + if (isImmutable && generatePIC) { + GraalInternalError.unimplemented(); + } else { + new SPARCMacroAssembler.Setx(constant.asInt(), asRegister(dest), true).emit(masm); + } + } else { + if (isImmutable && generatePIC) { + GraalInternalError.unimplemented(); + } else { + new SPARCMacroAssembler.Setx(constant.asLong(), asRegister(dest), true).emit(masm); + } + } + } else { + SPARCMove.move(crb, masm, dest, constant, SPARCDelayedControlTransfer.DUMMY); + } + } + + public Value getInput() { + return input; + } + + public AllocatableValue getResult() { + return result; + } + } + + public static final class CompressPointer extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + SPARCMove.move(crb, masm, result, input, SPARCDelayedControlTransfer.DUMMY); + + Register resReg = asRegister(result); + if (encoding.base != 0) { + Register baseReg = asRegister(baseRegister); + if (!nonNull) { + masm.cmp(resReg, baseReg); + masm.movcc(ConditionFlag.Equal, CC.Xcc, baseReg, resReg); + } + masm.sub(resReg, baseReg, resReg); + } + + if (encoding.shift != 0) { + masm.srlx(resReg, encoding.shift, resReg); + } + } + } + + public static final class UncompressPointer extends SPARCLIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); + + private final CompressEncoding encoding; + private final boolean nonNull; + + @Def({REG}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue input; + @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; + + public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { + super(TYPE); + this.result = result; + this.input = input; + this.baseRegister = baseRegister; + this.encoding = encoding; + this.nonNull = nonNull; + } + + @Override + public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + SPARCMove.move(crb, masm, result, input, SPARCDelayedControlTransfer.DUMMY); + + Register resReg = asRegister(result); + if (encoding.shift != 0) { + masm.sll(resReg, encoding.shift, resReg); + } + + if (encoding.base != 0) { + if (nonNull) { + masm.add(resReg, asRegister(baseRegister), resReg); + } else { + masm.cmp(resReg, resReg); + + Label done = new Label(); + masm.bpr(RCondition.Rc_nz, Annul.ANNUL, done, BranchPredict.PREDICT_TAKEN, resReg); + masm.add(asRegister(baseRegister), resReg, resReg); + masm.bind(done); + } + } + } + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -104,7 +104,7 @@ assert invokeKind.isDirect(); HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; - append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind)); + append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, runtime.getConfig())); } } @@ -117,7 +117,7 @@ Value targetAddressSrc = operand(callTarget.computedAddress()); AllocatableValue targetAddress = o7.asValue(targetAddressSrc.getLIRKind()); gen.emitMove(targetAddress, targetAddressSrc); - append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); + append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState, runtime.getConfig())); } @Override @@ -125,6 +125,10 @@ append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address)))); } + public void emitJumpToExceptionHandler(ValueNode address) { + append(new SPARCHotSpotJumpToExceptionHandlerOp(gen.load(operand(address)))); + } + @Override public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { Variable handler = gen.load(operand(handlerInCallerPc)); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.asm.sparc.*; import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.gen.*; @@ -64,7 +63,7 @@ public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, HotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) { new Setx(config.safepointPollingAddress, scratch).emit(masm); - MarkId.recordMark(crb, atReturn ? MarkId.POLL_RETURN_FAR : MarkId.POLL_FAR); + crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); final int pos = masm.position(); masm.ldx(new SPARCAddress(scratch, 0), g0); if (state != null) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -24,7 +24,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp; @@ -39,15 +39,17 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class); private final InvokeKind invokeKind; + private final HotSpotVMConfig config; - SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) { + SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) { super(TYPE, target, result, parameters, temps, state); assert invokeKind.isDirect(); this.invokeKind = invokeKind; + this.config = config; } @Override public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - MarkId.recordMark(crb, invokeKind == InvokeKind.Static ? MarkId.INVOKESTATIC : MarkId.INVOKESPECIAL); + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -27,9 +27,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.SPARCCall.DirectCallOp; @@ -57,7 +56,7 @@ public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { // The mark for an invocation that uses an inline cache must be placed at the // instruction that loads the Klass from the inline cache. - MarkId.recordMark(crb, invokeKind == InvokeKind.Virtual ? MarkId.INVOKEVIRTUAL : MarkId.INVOKEINTERFACE); + crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); Register scratchRegister = g5; new Setx(config.nonOopBits, scratchRegister, true).emit(masm); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; +import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.sparc.*; @@ -52,14 +52,17 @@ @Use({REG}) protected Value metaspaceMethod; - SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { + private final HotSpotVMConfig config; + + SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, HotSpotVMConfig config) { super(TYPE, targetMethod, result, parameters, temps, targetAddress, state); this.metaspaceMethod = metaspaceMethod; + this.config = config; } @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - MarkId.recordMark(crb, MarkId.INLINE_INVOKE); + crb.recordMark(config.MARKID_INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert !callReg.equals(METHOD); SPARCCall.indirectCall(crb, masm, callReg, callTarget, state); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -42,7 +42,7 @@ import com.oracle.graal.lir.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.options.*; import com.oracle.graal.options.OptionValue.OverrideScope; import com.oracle.graal.phases.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -31,6 +31,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.replacements.arraycopy.*; import com.oracle.graal.nodes.*; /** @@ -52,9 +53,14 @@ Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); LoweredCallTargetNode directCall = (LoweredCallTargetNode) invoke.callTarget(); JavaMethod callee = directCall.targetMethod(); - Assert.assertTrue(callee.getName().equals("")); - Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || - getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); + if (callee.getDeclaringClass().equals(getMetaAccess().lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { + // A partial snippet (e.g., ArrayCopySnippets.checkcastArraycopy) may + // call the original arraycopy method + } else { + Assert.assertTrue(callee.toString(), callee.getName().equals("")); + Assert.assertTrue(getMetaAccess().lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || + getMetaAccess().lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); + } } } } else { @@ -81,12 +87,9 @@ @Test public void test0() { - mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified // Array store checks test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); - - mustIntrinsify = true; } @Test @@ -145,25 +148,28 @@ @Test public void testObject() { - mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified - Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; testHelper("objectArraycopy", src); + } - mustIntrinsify = true; + /** + * Tests {@link ArrayCopySnippets#checkcastArraycopyWork(Object, int, Object, int, int)}. + */ + @Test + public void testArrayStoreException() { + Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; + Object[] dst = new CharSequence[src.length]; + // Will throw ArrayStoreException for 4th element + test("objectArraycopy", src, 0, dst, 0, src.length); } @Test public void testDisjointObject() { - mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified - Integer[] src1 = {1, 2, 3, 4}; test("objectArraycopy", src1, 0, src1, 1, src1.length - 1); Integer[] src2 = {1, 2, 3, 4}; test("objectArraycopy", src2, 1, src2, 0, src2.length - 1); - - mustIntrinsify = true; } @Test @@ -258,10 +264,8 @@ */ @Test public void testCopyRows() { - mustIntrinsify = false; Object[][] rows = {{"a1", "a2", "a3", "a4"}, {"b1", "b2", "b3", "b4"}, {"c1", "c2", "c3", "c4"}}; test("copyRows", rows, 4, new Integer(rows.length)); - mustIntrinsify = true; } public static Object[][] copyRows(Object[][] rows, int rowSize, Integer rowCount) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Thu May 28 17:44:05 2015 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.test; -import static com.oracle.graal.java.IntrinsicContext.*; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; import java.io.*; import java.lang.reflect.*; @@ -37,11 +37,10 @@ import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.StructuredGraph.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.phases.*; /** @@ -54,8 +53,9 @@ HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; HotSpotNmethod installedCode = new HotSpotNmethod(hsMethod, compResult.getName(), true); HotSpotCompiledNmethod compiledNmethod = new HotSpotCompiledNmethod(hsMethod, compResult); - CodeInstallResult result = runtime().getCompilerToVM().installCode(compiledNmethod, installedCode, null); - Assert.assertEquals("Error installing method " + method + ": " + result, result, CodeInstallResult.OK); + int result = runtime().getCompilerToVM().installCode(compiledNmethod, installedCode, null); + HotSpotVMConfig config = runtime().getConfig(); + Assert.assertEquals("Error installing method " + method + ": " + config.getCodeInstallResultDescription(result), result, config.codeInstallResultOk); // HotSpotRuntime hsRuntime = (HotSpotRuntime) getCodeCache(); // TTY.println(hsMethod.toString()); @@ -132,7 +132,7 @@ StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES); Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); - IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, ROOT_COMPILATION_BCI); + IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, ROOT_COMPILATION); new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); atLeastOneCompiled = true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -39,10 +39,11 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -37,7 +37,7 @@ import com.oracle.graal.hotspot.replacements.arraycopy.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu May 28 17:44:05 2015 +0200 @@ -31,7 +31,6 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.meta.HotSpotSuitesProvider.*; import static com.oracle.graal.nodes.StructuredGraph.*; -import static com.oracle.graal.phases.common.inlining.InliningUtil.*; import java.lang.management.*; import java.util.concurrent.*; @@ -116,7 +115,12 @@ /** * Time spent in compilation. */ - public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + private static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + + /** + * Meters the {@linkplain StructuredGraph#getBytecodeSize() bytecodes} compiled. + */ + private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes"); public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); @@ -151,8 +155,7 @@ public void runCompilation() { HotSpotVMConfig config = backend.getRuntime().getConfig(); final long threadId = Thread.currentThread().getId(); - long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue(); - long previousCompilationTime = CompilationTime.getCurrentValue(); + long startCompilationTime = System.nanoTime(); HotSpotInstalledCode installedCode = null; final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI; @@ -160,14 +163,14 @@ EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class); CompilationEvent compilationEvent = eventProvider.newCompilationEvent(); + // If there is already compiled code for this method on our level we simply return. + // Graal compiles are always at the highest compile level, even in non-tiered mode so we + // only need to check for that value. + if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { + return; + } + try (DebugCloseable a = CompilationTime.start()) { - // If there is already compiled code for this method on our level we simply return. - // Graal compiles are always at the highest compile level, even in non-tiered mode so we - // only need to check for that value. - if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { - return; - } - CompilationStatistics stats = CompilationStatistics.create(method, isOSR); final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); if (printCompilation) { @@ -183,14 +186,11 @@ // Begin the compilation event. compilationEvent.begin(); - boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0; - HotSpotProviders providers = backend.getProviders(); graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue())); - if (!recordEvolMethodDeps) { + if (shouldDisableMethodInliningRecording(config)) { graph.disableInlinedMethodRecording(); } - InlinedBytecodes.add(method.getCodeSize()); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) { // for OSR, only a pointer is passed to the method. @@ -270,7 +270,8 @@ System.exit(-1); } } finally { - final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes); + final int compiledBytecodes = graph.getBytecodeSize(); + CompiledBytecodes.add(compiledBytecodes); // Log a compilation event. if (compilationEvent.shouldWrite() && installedCode != null) { @@ -280,25 +281,40 @@ compilationEvent.setSucceeded(true); compilationEvent.setIsOsr(isOSR); compilationEvent.setCodeSize(installedCode.getSize()); - compilationEvent.setInlinedBytes(processedBytes); + compilationEvent.setInlinedBytes(compiledBytecodes); compilationEvent.commit(); } if (graalEnv != 0) { long ctask = unsafe.getAddress(graalEnv + config.graalEnvTaskOffset); assert ctask != 0L; - unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes); + unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes); } + long compilationTime = System.nanoTime() - startCompilationTime; if ((config.ciTime || config.ciTimeEach) && installedCode != null) { - long time = CompilationTime.getCurrentValue() - previousCompilationTime; - TimeUnit timeUnit = CompilationTime.getTimeUnit(); - long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS); + long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); CompilerToVM c2vm = backend.getRuntime().getCompilerToVM(); - c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode); + c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode); } } } + /** + * Determines whether to {@linkplain StructuredGraph#disableInlinedMethodRecording() disable} + * method inlining recording for the method being compiled. + * + * @see StructuredGraph#getBytecodeSize() + */ + private boolean shouldDisableMethodInliningRecording(HotSpotVMConfig config) { + if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) { + return false; + } + if (graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) { + return false; + } + return true; + } + private String getMethodDescription() { return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(), entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Thu May 28 17:44:05 2015 +0200 @@ -302,7 +302,7 @@ } if (excludeMethodFilters != null && excludeMethodFilters.length > 0) { String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")); - println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude); + println("CompileTheWorld : Excluding all methods matching one of the following filters: " + exclude); } println(); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot; - -import java.io.*; - -import com.oracle.graal.api.meta.Kind.FormatWithToString; - -/** - * Parent class for all HotSpot types that need to be serialized. - */ -public abstract class CompilerObject implements Serializable, FormatWithToString { - - private static final long serialVersionUID = -4551670987101214877L; -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Thu May 28 17:44:05 2015 +0200 @@ -64,8 +64,8 @@ /** * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the - * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a - * compiled method. + * {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled + * method. */ public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledCode.java Thu May 28 17:44:05 2015 +0200 @@ -36,24 +36,37 @@ import com.oracle.graal.api.code.CompilationResult.JumpTable; import com.oracle.graal.api.code.CompilationResult.Mark; import com.oracle.graal.api.code.CompilationResult.Site; +import com.oracle.graal.api.meta.Assumptions.Assumption; +import com.oracle.graal.api.meta.*; /** * A {@link CompilationResult} with additional HotSpot-specific information required for installing * the code in HotSpot's code cache. */ -public abstract class HotSpotCompiledCode extends CompilerObject { - - private static final long serialVersionUID = 7807321392203253218L; - public final CompilationResult comp; +public abstract class HotSpotCompiledCode { public final Site[] sites; public final ExceptionHandler[] exceptionHandlers; public final Comment[] comments; + public final Assumption[] assumptions; + + public final byte[] targetCode; + public final int targetCodeSize; public final byte[] dataSection; public final int dataSectionAlignment; public final DataPatch[] dataSectionPatches; + public final int totalFrameSize; + public final int customStackAreaOffset; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + public final ResolvedJavaMethod[] methods; + public static class Comment { public final String text; @@ -66,7 +79,6 @@ } public HotSpotCompiledCode(CompilationResult compResult) { - this.comp = compResult; sites = getSortedSites(compResult); if (compResult.getExceptionHandlers().isEmpty()) { exceptionHandlers = null; @@ -91,8 +103,12 @@ comments[i] = new Comment(annotation.position, text); } } + assumptions = compResult.getAssumptions(); assert validateFrames(); + targetCode = compResult.getTargetCode(); + targetCodeSize = compResult.getTargetCodeSize(); + DataSection data = compResult.getDataSection(); data.finalizeLayout(); dataSection = new byte[data.getSectionSize()]; @@ -103,6 +119,11 @@ dataSectionAlignment = data.getSectionAlignment(); dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]); + + totalFrameSize = compResult.getTotalFrameSize(); + customStackAreaOffset = compResult.getCustomStackAreaOffset(); + + methods = compResult.getMethods(); } /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java Thu May 28 17:44:05 2015 +0200 @@ -32,7 +32,6 @@ */ public final class HotSpotCompiledNmethod extends HotSpotCompiledCode { - private static final long serialVersionUID = 1492412603674834024L; public final HotSpotResolvedJavaMethod method; public final int entryBCI; public final int id; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java Thu May 28 17:44:05 2015 +0200 @@ -37,8 +37,6 @@ */ public final class HotSpotCompiledRuntimeStub extends HotSpotCompiledCode { - private static final long serialVersionUID = -4506206868419153274L; - public final String stubName; public HotSpotCompiledRuntimeStub(Stub stub, CompilationResult compResult) { @@ -55,7 +53,7 @@ // Stubs cannot be recompiled so they cannot be compiled with // assumptions and there is no point in recording evol_method dependencies - assert compResult.getAssumptions().isEmpty() : "stubs should not use assumptions: " + this; + assert compResult.getAssumptions() == null : "stubs should not use assumptions: " + this; assert compResult.getMethods() == null : "stubs should not record evol_method dependencies: " + this; for (DataPatch data : compResult.getDataPatches()) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -37,6 +37,10 @@ void emitPatchReturnAddress(ValueNode address); + default void emitJumpToExceptionHandler(ValueNode address) { + emitPatchReturnAddress(address); + } + void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); void emitPrefetchAllocate(ValueNode address, ValueNode distance); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Thu May 28 17:44:05 2015 +0200 @@ -25,13 +25,9 @@ import static com.oracle.graal.compiler.GraalDebugConfig.*; import static com.oracle.graal.options.OptionsLoader.*; -import java.lang.reflect.*; - import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; import com.oracle.graal.options.*; -import com.oracle.graal.phases.common.inlining.*; //JaCoCo Exclude @@ -43,13 +39,7 @@ private static final String GRAAL_OPTION_PREFIX = "-G:"; - private static native boolean isCITimingEnabled(); - static { - if (isCITimingEnabled()) { - unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes"); - unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime"); - } assert !Debug.Initialization.isDebugInitialized() : "The class " + Debug.class.getName() + " must not be initialized before the Graal runtime has been initialized. " + "This can be fixed by placing a call to " + Graal.class.getName() + ".runtime() on the path that triggers initialization of " + Debug.class.getName(); if (areDebugScopePatternsEnabled()) { @@ -70,34 +60,5 @@ OptionUtils.printFlags(options, GRAAL_OPTION_PREFIX); } - /** - * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric} - * associated with a field in a class will be unconditionally enabled when it is created. - *

    - * This method verifies that the named field exists and is of an expected type. However, it does - * not verify that the timer or metric created has the same name of the field. - * - * @param c the class in which the field is declared - * @param name the name of the field - */ - private static void unconditionallyEnableTimerOrMetric(Class c, String name) { - try { - Field field = c.getDeclaredField(name); - String propertyName; - if (DebugTimer.class.isAssignableFrom(field.getType())) { - propertyName = Debug.ENABLE_TIMER_PROPERTY_NAME_PREFIX + name; - } else { - assert DebugMetric.class.isAssignableFrom(field.getType()); - propertyName = Debug.ENABLE_METRIC_PROPERTY_NAME_PREFIX + name; - } - String previous = System.setProperty(propertyName, "true"); - if (previous != null) { - System.err.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\""); - } - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - public native Object getOptionValue(String optionName); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java Thu May 28 17:44:05 2015 +0200 @@ -22,15 +22,13 @@ */ package com.oracle.graal.hotspot; -import java.io.*; import java.util.*; import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -public final class HotSpotReferenceMap extends ReferenceMap implements Serializable { +public final class HotSpotReferenceMap extends ReferenceMap { static final int OOP64 = 0b1010; static final int OOP32 = 0b01; @@ -104,9 +102,7 @@ * map consists of 4 bit entries that represent 8 bytes of memory. * */ - class HotSpotOopMap implements Cloneable, Serializable { - - private static final long serialVersionUID = -4997600265320131213L; + class HotSpotOopMap implements Cloneable { /** * Each entry is 4 bits long and covers 8 bytes of memory. @@ -282,8 +278,6 @@ } } - private static final long serialVersionUID = -1052183095979496819L; - /** * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a * 64-bit system, a 256-bit vector register requires 12 reference map bits). @@ -352,7 +346,7 @@ private void set(HotSpotOopMap refMap, int index, LIRKind kind) { if (kind.isDerivedReference()) { - throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap"); + throw new InternalError("derived reference cannot be inserted in ReferenceMap"); } int bytesPerElement = bytesPerElement(kind); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Thu May 28 17:44:05 2015 +0200 @@ -27,7 +27,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; @@ -63,10 +62,6 @@ return null; } } - } else if (substituteClass == CRC32Substitutions.class) { - if (!config.useCRC32Intrinsics) { - return null; - } } return super.registerMethodSubstitution(cr, originalMethod, substituteMethod); } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu May 28 17:44:05 2015 +0200 @@ -39,9 +39,7 @@ * * All non-static, public fields in this class are so that they can be compiled as constants. */ -public class HotSpotVMConfig extends CompilerObject { - - private static final long serialVersionUID = -4744897993263044184L; +public class HotSpotVMConfig { /** * Determines if the current architecture is included in a given architecture set specification. @@ -1511,26 +1509,49 @@ @HotSpotVMConstant(name = "GraalEnv::cache_full") @Stable public int codeInstallResultCacheFull; @HotSpotVMConstant(name = "GraalEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge; + public String getCodeInstallResultDescription(int codeInstallResult) { + if (codeInstallResult == codeInstallResultOk) { + return "ok"; + } + if (codeInstallResult == codeInstallResultDependenciesFailed) { + return "dependencies failed"; + } + if (codeInstallResult == codeInstallResultDependenciesInvalid) { + return "dependencies invalid"; + } + if (codeInstallResult == codeInstallResultCacheFull) { + return "code cache is full"; + } + if (codeInstallResult == codeInstallResultCodeTooLarge) { + return "code is too large"; + } + assert false : codeInstallResult; + return "unknown"; + } + @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; - @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int codeInstallerMarkIdVerifiedEntry; - @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int codeInstallerMarkIdUnverifiedEntry; - @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int codeInstallerMarkIdOsrEntry; - @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int codeInstallerMarkIdExceptionHandlerEntry; - @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int codeInstallerMarkIdDeoptHandlerEntry; - @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int codeInstallerMarkIdInvokeinterface; - @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int codeInstallerMarkIdInvokevirtual; - @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int codeInstallerMarkIdInvokestatic; - @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int codeInstallerMarkIdInvokespecial; - @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int codeInstallerMarkIdInlineInvoke; - @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int codeInstallerMarkIdPollNear; - @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int codeInstallerMarkIdPollReturnNear; - @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int codeInstallerMarkIdPollFar; - @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int codeInstallerMarkIdPollReturnFar; - @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_SHIFT") @Stable public int codeInstallerMarkIdCardTableShift; - @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int codeInstallerMarkIdCardTableAddress; - @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int codeInstallerMarkIdInvokeInvalid; + // Checkstyle: stop + @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int MARKID_OSR_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int MARKID_EXCEPTION_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int MARKID_DEOPT_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int MARKID_INVOKEINTERFACE; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int MARKID_INVOKEVIRTUAL; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int MARKID_INVOKESTATIC; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int MARKID_INVOKESPECIAL; + @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int MARKID_INLINE_INVOKE; + @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int MARKID_POLL_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int MARKID_POLL_RETURN_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int MARKID_POLL_FAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int MARKID_POLL_RETURN_FAR; + @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_SHIFT") @Stable public int MARKID_CARD_TABLE_SHIFT; + @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int MARKID_CARD_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int MARKID_INVOKE_INVALID; + + // Checkstyle: resume public boolean check() { for (Field f : getClass().getDeclaredFields()) { diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Thu May 28 17:44:05 2015 +0200 @@ -27,9 +27,9 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; + import com.oracle.graal.hotspotvmconfig.*; /** @@ -176,66 +176,19 @@ Object lookupAppendixInPool(long metaspaceConstantPool, int cpi); - public enum CodeInstallResult { - OK("ok"), - DEPENDENCIES_FAILED("dependencies failed"), - DEPENDENCIES_INVALID("dependencies invalid"), - CACHE_FULL("code cache is full"), - CODE_TOO_LARGE("code is too large"); - - private int value; - private String message; - - private CodeInstallResult(String name) { - HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig(); - switch (name) { - case "ok": - this.value = config.codeInstallResultOk; - break; - case "dependencies failed": - this.value = config.codeInstallResultDependenciesFailed; - break; - case "dependencies invalid": - this.value = config.codeInstallResultDependenciesInvalid; - break; - case "code cache is full": - this.value = config.codeInstallResultCacheFull; - break; - case "code is too large": - this.value = config.codeInstallResultCodeTooLarge; - break; - default: - throw GraalInternalError.shouldNotReachHere("unknown enum name " + name); - } - this.message = name; - } - - /** - * Returns the enum object for the given value. - */ - public static CodeInstallResult getEnum(int value) { - for (CodeInstallResult e : values()) { - if (e.value == value) { - return e; - } - } - throw GraalInternalError.shouldNotReachHere("unknown enum value " + value); - } - - @Override - public String toString() { - return message; - } - } - /** * Installs the result of a compilation into the code cache. * * @param compiledCode the result of a compilation * @param code the details of the installed CodeBlob are written to this object - * @return the outcome of the installation as a {@link CodeInstallResult}. + * @return the outcome of the installation which will be one of + * {@link HotSpotVMConfig#codeInstallResultOk}, + * {@link HotSpotVMConfig#codeInstallResultCacheFull}, + * {@link HotSpotVMConfig#codeInstallResultCodeTooLarge}, + * {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or + * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. */ - CodeInstallResult installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); + int installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); /** * Notifies the VM of statistics for a completed compilation. @@ -294,8 +247,8 @@ long readUnsafeKlassPointer(Object o); /** - * Reads an object pointer within a VM data structures. That is, any {@link HotSpotVMField} - * whose {@link HotSpotVMField#type() type} is {@code "oop"} (e.g., + * Reads an object pointer within a VM data structure. That is, any {@link HotSpotVMField} whose + * {@link HotSpotVMField#type() type} is {@code "oop"} (e.g., * {@code ArrayKlass::_component_mirror}, {@code Klass::_java_mirror}, * {@code JavaThread::_threadObj}). * diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Thu May 28 17:44:05 2015 +0200 @@ -45,12 +45,8 @@ } } - private native int installCode0(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); - @Override - public CodeInstallResult installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog) { - return CodeInstallResult.getEnum(installCode0(compiledCode, code, speculationLog)); - } + public native int installCode(HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); @Override public native long getMetaspaceMethod(Class holder, int slot); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.debug; - -import com.oracle.graal.api.meta.*; - -public class LineNumberTableImpl implements LineNumberTable { - - private final int[] lineNumbers; - private final int[] bci; - - public LineNumberTableImpl(int[] lineNumbers, int[] bci) { - this.lineNumbers = lineNumbers; - this.bci = bci; - } - - @Override - public int[] getLineNumberEntries() { - return lineNumbers; - } - - @Override - public int[] getBciEntries() { - return bci; - } - - @Override - public int getLineNumber(@SuppressWarnings("hiding") int bci) { - for (int i = 0; i < this.bci.length - 1; i++) { - if (this.bci[i] <= bci && bci < this.bci[i + 1]) { - return lineNumbers[i]; - } - } - return lineNumbers[lineNumbers.length - 1]; - } -} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.debug; - -import com.oracle.graal.api.meta.*; - -public class LocalImpl implements Local { - - private final String name; - private final int startBci; - private final int endBci; - private final int slot; - private final JavaType type; - - public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { - this.name = name; - this.startBci = startBci; - this.endBci = endBci; - this.slot = slot; - this.type = type; - } - - @Override - public int getStartBCI() { - return startBci; - } - - @Override - public int getEndBCI() { - return endBci; - } - - @Override - public String getName() { - return name; - } - - @Override - public JavaType getType() { - return type; - } - - @Override - public int getSlot() { - return slot; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof LocalImpl)) { - return false; - } - LocalImpl that = (LocalImpl) obj; - return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public String toString() { - return "LocalImpl"; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.debug; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -public class LocalVariableTableImpl implements LocalVariableTable { - - private final Local[] locals; - - public LocalVariableTableImpl(Local[] locals) { - this.locals = locals; - } - - @Override - public Local getLocal(int slot, int bci) { - Local result = null; - for (Local local : locals) { - if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { - if (result == null) { - result = local; - } else { - throw new IllegalStateException("Locals overlap!"); - } - } - } - return result; - } - - @Override - public Local[] getLocals() { - return locals; - } - - @Override - public Local[] getLocalsAt(int bci) { - List result = new ArrayList<>(); - for (Local l : locals) { - if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { - result.add(l); - } - } - return result.toArray(new Local[result.size()]); - } - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -41,11 +41,12 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.replacements.arraycopy.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; @@ -68,6 +69,7 @@ protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; protected UnsafeLoadSnippets.Templates unsafeLoadSnippets; protected AssertionSnippets.Templates assertionSnippets; + protected ArrayCopySnippets.Templates arraycopySnippets; public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) { @@ -89,6 +91,7 @@ exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target); unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target); assertionSnippets = new AssertionSnippets.Templates(providers, target); + arraycopySnippets = new ArrayCopySnippets.Templates(providers, target); providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target)); } @@ -154,6 +157,12 @@ if (graph.getGuardsStage().areFrameStatesAtDeopts()) { monitorSnippets.lower((MonitorExitNode) n, tool); } + } else if (n instanceof ArrayCopyNode) { + arraycopySnippets.lower((ArrayCopyNode) n, tool); + } else if (n instanceof ArrayCopySlowPathNode) { + ArrayCopySlowPathNode slowpath = (ArrayCopySlowPathNode) n; + // FrameState stateAfter = slowpath.stateAfter(); + arraycopySnippets.lower(slowpath, tool); } else if (n instanceof G1PreWriteBarrier) { writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool); } else if (n instanceof G1PostWriteBarrier) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java Thu May 28 17:44:05 2015 +0200 @@ -42,9 +42,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; -import com.oracle.graal.java.*; -import com.oracle.graal.lir.asm.*; import com.oracle.graal.printer.*; /** @@ -53,65 +50,17 @@ public class HotSpotCodeCacheProvider implements CodeCacheProvider { protected final HotSpotGraalRuntimeProvider runtime; + public final HotSpotVMConfig config; protected final TargetDescription target; protected final RegisterConfig regConfig; - public HotSpotCodeCacheProvider(HotSpotGraalRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + public HotSpotCodeCacheProvider(HotSpotGraalRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) { this.runtime = runtime; + this.config = config; this.target = target; this.regConfig = regConfig; } - /** - * Constants used to mark special positions in code being installed into the code cache by Graal - * C++ code. - */ - public enum MarkId { - VERIFIED_ENTRY(config().codeInstallerMarkIdVerifiedEntry), - UNVERIFIED_ENTRY(config().codeInstallerMarkIdUnverifiedEntry), - OSR_ENTRY(config().codeInstallerMarkIdOsrEntry), - EXCEPTION_HANDLER_ENTRY(config().codeInstallerMarkIdExceptionHandlerEntry), - DEOPT_HANDLER_ENTRY(config().codeInstallerMarkIdDeoptHandlerEntry), - INVOKEINTERFACE(config().codeInstallerMarkIdInvokeinterface), - INVOKEVIRTUAL(config().codeInstallerMarkIdInvokevirtual), - INVOKESTATIC(config().codeInstallerMarkIdInvokestatic), - INVOKESPECIAL(config().codeInstallerMarkIdInvokespecial), - INLINE_INVOKE(config().codeInstallerMarkIdInlineInvoke), - POLL_NEAR(config().codeInstallerMarkIdPollNear), - POLL_RETURN_NEAR(config().codeInstallerMarkIdPollReturnNear), - POLL_FAR(config().codeInstallerMarkIdPollFar), - POLL_RETURN_FAR(config().codeInstallerMarkIdPollReturnFar), - CARD_TABLE_SHIFT(config().codeInstallerMarkIdCardTableShift), - CARD_TABLE_ADDRESS(config().codeInstallerMarkIdCardTableAddress); - - private final int value; - - private MarkId(int value) { - this.value = value; - } - - private static HotSpotVMConfig config() { - return HotSpotGraalRuntime.runtime().getConfig(); - } - - public static MarkId getEnum(int value) { - for (MarkId e : values()) { - if (e.value == value) { - return e; - } - } - throw GraalInternalError.shouldNotReachHere("unknown enum value " + value); - } - - /** - * Helper method to {@link CompilationResultBuilder#recordMark(Object) record a mark} with a - * {@link CompilationResultBuilder}. - */ - public static void recordMark(CompilationResultBuilder crb, MarkId mark) { - crb.recordMark(mark.value); - } - } - @Override public String disassemble(CompilationResult compResult, InstalledCode installedCode) { byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); @@ -144,7 +93,7 @@ hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); } for (Mark mark : compResult.getMarks()) { - hcf.addComment(mark.pcOffset, MarkId.getEnum((int) mark.id).toString()); + hcf.addComment(mark.pcOffset, getMarkIdName((int) mark.id)); } } String hcfEmbeddedString = hcf.toEmbeddedString(); @@ -181,6 +130,22 @@ } } + private String getMarkIdName(int markId) { + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().startsWith("MARKID_")) { + f.setAccessible(true); + try { + if (f.getInt(runtime.getConfig()) == markId) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return String.valueOf(markId); + } + /** * Decodes a call target to a mnemonic if possible. */ @@ -260,18 +225,19 @@ installedCode = code; } HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult); - CodeInstallResult result = runtime.getCompilerToVM().installCode(compiledCode, installedCode, log); - if (result != CodeInstallResult.OK) { + int result = runtime.getCompilerToVM().installCode(compiledCode, installedCode, log); + if (result != config.codeInstallResultOk) { String msg = compiledCode.getInstallationFailureMessage(); + String resultDesc = config.getCodeInstallResultDescription(result); if (msg != null) { - msg = String.format("Code installation failed: %s%n%s", result, msg); + msg = String.format("Code installation failed: %s%n%s", resultDesc, msg); } else { - msg = String.format("Code installation failed: %s", result); + msg = String.format("Code installation failed: %s", resultDesc); } - if (result == CodeInstallResult.DEPENDENCIES_INVALID) { - throw new AssertionError(result + " " + msg); + if (result == config.codeInstallResultDependenciesInvalid) { + throw new AssertionError(resultDesc + " " + msg); } - throw new BailoutException(result != CodeInstallResult.DEPENDENCIES_FAILED, msg); + throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg); } return logOrDump(installedCode, compResult); } @@ -290,8 +256,8 @@ HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true); HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult); CompilerToVM vm = runtime.getCompilerToVM(); - CodeInstallResult result = vm.installCode(compiled, code, null); - if (result != CodeInstallResult.OK) { + int result = vm.installCode(compiled, code, null); + if (result != runtime.getConfig().codeInstallResultOk) { return null; } return code; @@ -361,10 +327,6 @@ return null; } - public String disassemble(ResolvedJavaMethod method) { - return new BytecodeDisassembler().disassemble(method); - } - public SpeculationLog createSpeculationLog() { return new HotSpotSpeculationLog(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant.java Thu May 28 17:44:05 2015 +0200 @@ -29,8 +29,6 @@ */ public final class HotSpotCompressedNullConstant extends AbstractValue implements JavaConstant, HotSpotConstant { - private static final long serialVersionUID = 8906209595800783961L; - public static final JavaConstant COMPRESSED_NULL = new HotSpotCompressedNullConstant(); private HotSpotCompressedNullConstant() { diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Thu May 28 17:44:05 2015 +0200 @@ -35,9 +35,7 @@ /** * Implementation of {@link ConstantPool} for HotSpot. */ -public class HotSpotConstantPool extends CompilerObject implements ConstantPool, HotSpotProxified { - - private static final long serialVersionUID = -5443206401485234850L; +public class HotSpotConstantPool implements ConstantPool, HotSpotProxified { /** * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and @@ -115,13 +113,23 @@ } } + private static class LookupTypeCacheElement { + int lastCpi = Integer.MIN_VALUE; + JavaType javaType; + + public LookupTypeCacheElement(int lastCpi, JavaType javaType) { + super(); + this.lastCpi = lastCpi; + this.javaType = javaType; + } + } + /** * Reference to the C++ ConstantPool object. */ private final long metaspaceConstantPool; private final Object[] cache; - private ResolvedJavaType lastType; - private int lastTypeCpi = Integer.MIN_VALUE; + private volatile LookupTypeCacheElement lastLookupType; public HotSpotConstantPool(long metaspaceConstantPool) { this.metaspaceConstantPool = metaspaceConstantPool; @@ -489,22 +497,17 @@ @Override public JavaType lookupType(int cpi, int opcode) { - if (cpi == this.lastTypeCpi) { - synchronized (this) { - if (cpi == this.lastTypeCpi) { - return this.lastType; - } + final LookupTypeCacheElement elem = this.lastLookupType; + if (elem != null && elem.lastCpi == cpi) { + return elem.javaType; + } else { + final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi); + JavaType result = getJavaType(metaspacePointer); + if (result instanceof ResolvedJavaType) { + this.lastLookupType = new LookupTypeCacheElement(cpi, result); } + return result; } - final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi); - JavaType result = getJavaType(metaspacePointer); - if (result instanceof ResolvedJavaType) { - synchronized (this) { - this.lastType = (ResolvedJavaType) result; - this.lastTypeCpi = cpi; - } - } - return result; } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Thu May 28 17:44:05 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** @@ -97,6 +96,40 @@ return null; } + /** + * Try to convert {@code offset} into an an index into {@code array}. + * + * @return -1 if the offset isn't within the array or the computed index + */ + private int indexForOffset(JavaConstant array, long offset) { + if (array.getKind() != Kind.Object || array.isNull()) { + return -1; + } + Class componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType(); + Kind kind = runtime.getHostProviders().getMetaAccess().lookupJavaType(componentType).getKind(); + int arraybase = runtime.getArrayBaseOffset(kind); + int scale = runtime.getArrayIndexScale(kind); + if (offset < arraybase) { + return -1; + } + long index = offset - arraybase; + if (index % scale != 0) { + return -1; + } + long result = index / scale; + if (result >= Integer.MAX_VALUE) { + return -1; + } + return (int) result; + } + + public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + return readConstantArrayElement(array, indexForOffset(array, offset)); + } + return null; + } + @Override public JavaConstant readArrayElement(JavaConstant array, int index) { if (array.getKind() != Kind.Object || array.isNull()) { @@ -198,8 +231,7 @@ assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || HotSpotLoadFieldPlugin.FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver; HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; - if (receiver == null) { - assert hotspotField.isStatic(); + if (hotspotField.isStatic()) { if (hotspotField.isFinal() || hotspotField.isStable()) { ResolvedJavaType holder = hotspotField.getDeclaringClass(); if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable(hotspotField)) { @@ -214,7 +246,6 @@ * for non-static final fields, we must assume that they are only initialized if they * have a non-default value. */ - assert !hotspotField.isStatic(); Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); // Canonicalization may attempt to process an unsafe read before @@ -260,18 +291,17 @@ private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; - if (receiver == null) { - assert hotspotField.isStatic(); + if (hotspotField.isStatic()) { HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); if (holder.isInitialized()) { return memoryAccess.readUnsafeConstant(hotspotField.getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); } - return null; } else { - assert !hotspotField.isStatic(); - assert receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object()); - return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset()); + if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) { + return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset()); + } } + return null; } public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { @@ -314,7 +344,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2015, 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 @@ -26,6 +26,7 @@ import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; import java.lang.invoke.*; +import java.util.zip.*; import sun.reflect.*; @@ -42,8 +43,8 @@ import com.oracle.graal.hotspot.replacements.arraycopy.*; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.options.*; @@ -65,7 +66,7 @@ */ public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) { - InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess()); + InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess); Plugins plugins = new Plugins(invocationPlugins); NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider); @@ -76,7 +77,8 @@ plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); plugins.setTypeCheckPlugin(wordOperationPlugin); plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); - plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin)); + plugins.setGenericInvocationPlugin(new MethodHandleInvocationPlugin(constantReflection.getMethodHandleAccess(), new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, + wordOperationPlugin))); registerObjectPlugins(invocationPlugins); registerClassPlugins(plugins); @@ -86,6 +88,7 @@ registerReflectionPlugins(invocationPlugins); registerStableOptionPlugins(invocationPlugins); registerAESPlugins(invocationPlugins, config); + registerCRC32Plugins(invocationPlugins, config); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, !config.useHeapProfiler); return plugins; @@ -187,7 +190,7 @@ }); r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { - b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length)); + b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length)); return true; } @@ -248,4 +251,17 @@ } } } + + private static void registerCRC32Plugins(InvocationPlugins plugins, HotSpotVMConfig config) { + if (config.useCRC32Intrinsics) { + assert config.aescryptEncryptBlockStub != 0L; + assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; + Registration r = new Registration(plugins, CRC32.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class); + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu May 28 17:44:05 2015 +0200 @@ -71,11 +71,16 @@ return checkcastArraycopyDescriptors[uninit ? 1 : 0]; } - public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit) { + public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny) { if (uninit) { assert kind == Kind.Object; + assert !killAny : "unsupported"; return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0]; } + if (killAny) { + assert kind == Kind.Object; + return objectArraycopyDescriptorsKillAny[aligned ? 1 : 0][disjoint ? 1 : 0]; + } return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind); } @@ -83,6 +88,7 @@ private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2]; private static final ForeignCallDescriptor[] checkcastArraycopyDescriptors = new ForeignCallDescriptor[2]; + private static ForeignCallDescriptor[][] objectArraycopyDescriptorsKillAny = new ForeignCallDescriptor[2][2]; static { // Populate the EnumMap instances @@ -93,13 +99,10 @@ } } - private void registerArraycopyDescriptor(Map descMap, Kind kind, boolean aligned, boolean disjoint, boolean uninit, long routine) { + private void registerArraycopyDescriptor(Map descMap, Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) { ForeignCallDescriptor desc = descMap.get(routine); if (desc == null) { - String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy"; - desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class); - LocationIdentity killed = NamedLocationIdentity.getArrayLocation(kind); - registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + desc = buildDescriptor(kind, aligned, disjoint, uninit, killAny, routine); descMap.put(routine, desc); } if (uninit) { @@ -110,6 +113,15 @@ } } + private ForeignCallDescriptor buildDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) { + assert !killAny || kind == Kind.Object; + String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy" + (killAny ? "KillAny" : ""); + ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class); + LocationIdentity killed = killAny ? LocationIdentity.any() : NamedLocationIdentity.getArrayLocation(kind); + registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed); + return desc; + } + private void registerCheckcastArraycopyDescriptor(boolean uninit, long routine) { String name = "Object" + (uninit ? "Uninit" : "") + "Checkcast"; // Input: @@ -125,15 +137,28 @@ checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc; } - private void registerArrayCopy(Map descMap, Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { - registerArrayCopy(descMap, kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false); + private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { + registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false); } - private void registerArrayCopy(Map descMap, Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) { - registerArraycopyDescriptor(descMap, kind, false, false, uninit, routine); - registerArraycopyDescriptor(descMap, kind, true, false, uninit, alignedRoutine); - registerArraycopyDescriptor(descMap, kind, false, true, uninit, disjointRoutine); - registerArraycopyDescriptor(descMap, kind, true, true, uninit, alignedDisjointRoutine); + private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) { + /* + * Sometimes the same function is used for multiple cases so share them when that's the case + * but only within the same Kind. For instance short and char are the same copy routines but + * they kill different memory so they still have to be distinct. + */ + Map descMap = new HashMap<>(); + registerArraycopyDescriptor(descMap, kind, false, false, uninit, false, routine); + registerArraycopyDescriptor(descMap, kind, true, false, uninit, false, alignedRoutine); + registerArraycopyDescriptor(descMap, kind, false, true, uninit, false, disjointRoutine); + registerArraycopyDescriptor(descMap, kind, true, true, uninit, false, alignedDisjointRoutine); + + if (kind == Kind.Object && !uninit) { + objectArraycopyDescriptorsKillAny[0][0] = buildDescriptor(kind, false, false, uninit, true, routine); + objectArraycopyDescriptorsKillAny[1][0] = buildDescriptor(kind, true, false, uninit, true, alignedRoutine); + objectArraycopyDescriptorsKillAny[0][1] = buildDescriptor(kind, false, true, uninit, true, disjointRoutine); + objectArraycopyDescriptorsKillAny[1][1] = buildDescriptor(kind, true, true, uninit, true, alignedDisjointRoutine); + } } public void initialize(HotSpotProviders providers, HotSpotVMConfig c) { @@ -205,19 +230,16 @@ linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any()); - // sometimes the same function is used for different kinds of arraycopy so check for - // duplicates using a map. - Map descMap = new HashMap<>(); - registerArrayCopy(descMap, Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy); - registerArrayCopy(descMap, Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true); + registerArrayCopy(Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy); + registerArrayCopy(Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy); + registerArrayCopy(Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy); + registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy); + registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy); + registerArrayCopy(Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true); registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit); registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Thu May 28 17:44:05 2015 +0200 @@ -22,23 +22,14 @@ */ package com.oracle.graal.hotspot.meta; -import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*; - -import java.lang.invoke.*; -import java.util.*; - import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin; import com.oracle.graal.replacements.nodes.*; @@ -48,12 +39,10 @@ */ final class HotSpotInvocationPlugins extends InvocationPlugins { final HotSpotVMConfig config; - final MethodHandleAccessProvider methodHandleAccess; - public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) { + public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) { super(metaAccess); this.config = config; - this.methodHandleAccess = methodHandleAccess; } @Override @@ -74,68 +63,6 @@ super.register(plugin, declaringClass, name, argumentTypes); } - private ResolvedJavaType methodHandleClass; - private final Map methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class); - - @Override - public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) { - if (methodHandleClass == null) { - methodHandleClass = plugins.getMetaAccess().lookupJavaType(MethodHandle.class); - } - if (method.getDeclaringClass().equals(methodHandleClass)) { - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; - int intrinsicId = hsMethod.intrinsicId(); - if (intrinsicId != 0) { - /* - * The methods of MethodHandle that need substitution are signature-polymorphic, - * i.e., the VM replicates them for every signature that they are actually used for. - */ - IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId); - if (intrinsicMethod != null) { - InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod); - if (plugin == null) { - plugin = new InvocationPlugin() { - public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) { - InvokeKind invokeKind = b.getInvokeKind(); - if (invokeKind != InvokeKind.Static) { - receiver.get(); - } - JavaType invokeReturnType = b.getInvokeReturnType(); - InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod, - b.bci(), invokeReturnType, argsIncludingReceiver); - if (invoke == null) { - MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), invokeReturnType, argsIncludingReceiver); - if (invokeReturnType.getKind() == Kind.Void) { - b.add(methodHandleNode); - } else { - b.addPush(methodHandleNode); - } - } else { - CallTargetNode callTarget = invoke.callTarget(); - NodeInputList argumentsList = callTarget.arguments(); - ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]); - for (ValueNode arg : args) { - b.recursiveAppend(arg); - } - b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args); - } - return true; - } - - public boolean isSignaturePolymorphic() { - return true; - } - }; - methodHandlePlugins.put(intrinsicMethod, plugin); - } - return plugin; - } - } - - } - return super.lookupInvocation(method); - } - @Override public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { for (Node node : newNodes) { @@ -154,7 +81,10 @@ if (isClass(c)) { // This will be handled later by LoadJavaMirrorWithKlassPhase } else { - throw new AssertionError("illegal constant node in AOT: " + node); + // Tolerate uses in unused FrameStates + if (node.usages().filter((n) -> !(n instanceof FrameState) || n.hasUsages()).isNotEmpty()) { + throw new AssertionError("illegal constant node in AOT: " + node); + } } } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotJavaType.java Thu May 28 17:44:05 2015 +0200 @@ -23,14 +23,11 @@ package com.oracle.graal.hotspot.meta; import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; /** * Common base class for all HotSpot {@link JavaType} implementations. */ -public abstract class HotSpotJavaType extends CompilerObject implements JavaType { - - private static final long serialVersionUID = -4252886265301910771L; +public abstract class HotSpotJavaType implements JavaType { private final String name; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -25,7 +25,6 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.nodes.*; @@ -41,7 +40,7 @@ static final ThreadLocal FieldReadEnabledInImmutableCode = new ThreadLocal<>(); public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { - if (!ImmutableCode.getValue() || b.parsingReplacement()) { + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { if (receiver.isConstant()) { JavaConstant asJavaConstant = receiver.asJavaConstant(); return tryReadField(b, field, asJavaConstant); @@ -64,19 +63,7 @@ } public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) { - if (!ImmutableCode.getValue() || b.parsingReplacement()) { - // Javac does not allow use of "$assertionsDisabled" for a field name but - // Eclipse does in which case a suffix is added to the generated field. - if (b.parsingReplacement() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) { - // For methods called indirectly from intrinsics, we (silently) disable - // assertions so that the parser won't see calls to the AssertionError - // constructor (all Invokes must be removed from intrinsics - see - // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of - // assertions in intrinsics is forbidden. - assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)"); - b.addPush(ConstantNode.forBoolean(true)); - return true; - } + if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { return tryReadField(b, staticField, null); } return false; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadIndexedPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -40,7 +40,7 @@ } public boolean apply(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) { - if (b.parsingReplacement()) { + if (b.parsingIntrinsic()) { ResolvedJavaType arrayType = StampTool.typeOrNull(array); /* * There are cases where the array does not have a known type yet, i.e., the type is diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl.java Thu May 28 17:44:05 2015 +0200 @@ -30,8 +30,6 @@ public final class HotSpotMetaspaceConstantImpl extends PrimitiveConstant implements HotSpotMetaspaceConstant, VMConstant, HotSpotProxified { - private static final long serialVersionUID = 1003463314013122983L; - static HotSpotMetaspaceConstantImpl forMetaspaceObject(Kind kind, long primitive, Object metaspaceObject, boolean compressed) { return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethod.java Thu May 28 17:44:05 2015 +0200 @@ -28,11 +28,9 @@ import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; -public abstract class HotSpotMethod extends CompilerObject implements JavaMethod, Formattable { +public abstract class HotSpotMethod implements JavaMethod, Formattable { - private static final long serialVersionUID = 7167491397941960839L; protected String name; /** diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Thu May 28 17:44:05 2015 +0200 @@ -39,9 +39,7 @@ /** * Access to a HotSpot MethodData structure (defined in methodData.hpp). */ -public final class HotSpotMethodData extends CompilerObject { - - private static final long serialVersionUID = -8873133496591225071L; +public final class HotSpotMethodData { private static final HotSpotVMConfig config = runtime().getConfig(); private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,6 @@ */ public final class HotSpotMethodUnresolved extends HotSpotMethod { - private static final long serialVersionUID = 5610263481791970079L; private final Signature signature; protected JavaType holder; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java Thu May 28 17:44:05 2015 +0200 @@ -37,8 +37,6 @@ */ public final class HotSpotObjectConstantImpl extends AbstractValue implements HotSpotObjectConstant, HotSpotProxified { - private static final long serialVersionUID = 3592151693708093496L; - static JavaConstant forObject(Object object) { return forObject(object, false); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotParameterPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -38,7 +38,7 @@ } public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) { - if (b.parsingReplacement()) { + if (b.parsingIntrinsic()) { ResolvedJavaType type = StampTool.typeOrNull(stamp); if (wordTypes.isWord(type)) { return new ParameterNode(index, wordTypes.getWordStamp(type)); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Thu May 28 17:44:05 2015 +0200 @@ -27,9 +27,8 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; -public final class HotSpotProfilingInfo extends CompilerObject implements ProfilingInfo, HotSpotProxified { +public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified { - private static final long serialVersionUID = -8307682725047864875L; private static final DebugMetric metricInsufficentSpace = Debug.metric("InsufficientSpaceForProfilingData"); private final HotSpotMethodData methodData; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Thu May 28 17:44:05 2015 +0200 @@ -36,9 +36,8 @@ /** * Represents a field in a HotSpot type. */ -public class HotSpotResolvedJavaFieldImpl extends CompilerObject implements HotSpotResolvedJavaField, HotSpotProxified { +public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { - private static final long serialVersionUID = 7692985878836955683L; private final HotSpotResolvedObjectTypeImpl holder; private final String name; private JavaType type; @@ -54,11 +53,15 @@ HotSpotResolvedJavaField inner; public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { - super(false); this.inner = inner; } @Override + public boolean isImmutable() { + return false; + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Thu May 28 17:44:05 2015 +0200 @@ -36,7 +36,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.nodes.*; /** @@ -44,8 +43,6 @@ */ public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MethodIdHolder { - private static final long serialVersionUID = -5486975070147586588L; - /** * Reference to metaspace Method object. */ diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java Thu May 28 17:44:05 2015 +0200 @@ -28,8 +28,6 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { - private static final long serialVersionUID = -6410840212023428347L; - /** * Gets the Graal mirror for a {@link Class} object. * diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl.java Thu May 28 17:44:05 2015 +0200 @@ -42,8 +42,6 @@ */ public final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified { - private static final long serialVersionUID = 3481514353553840471L; - /** * The Java class this type represents. */ diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Thu May 28 17:44:05 2015 +0200 @@ -38,7 +38,6 @@ */ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType implements HotSpotProxified { - private static final long serialVersionUID = -6208552348908071473L; private final Kind kind; /** diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Thu May 28 17:44:05 2015 +0200 @@ -31,9 +31,8 @@ /** * Represents a method signature. */ -public class HotSpotSignature extends CompilerObject implements Signature { +public class HotSpotSignature implements Signature { - private static final long serialVersionUID = -2890917956072366116L; private final List parameters = new ArrayList<>(); private final String returnType; private final String originalString; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Thu May 28 17:44:05 2015 +0200 @@ -119,7 +119,7 @@ * for equality. */ private boolean appendGraphEncoderTest(PhaseSuite suite) { - suite.appendPhase(new BasePhase() { + suite.appendPhase(new BasePhase("VerifyEncodingDecoding") { @Override protected void run(StructuredGraph graph, HighTierContext context) { EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedJavaType.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,6 @@ */ public class HotSpotUnresolvedJavaType extends HotSpotJavaType { - private static final long serialVersionUID = -2320936267633521314L; private final HotSpotGraalRuntimeProvider runtime; public HotSpotUnresolvedJavaType(String name, HotSpotGraalRuntimeProvider runtime) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotWordOperationPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2015, 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 @@ -35,9 +35,10 @@ import com.oracle.graal.hotspot.word.*; import com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -28,8 +28,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -32,7 +32,7 @@ import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -27,8 +27,8 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Thu May 28 17:44:05 2015 +0200 @@ -26,8 +26,8 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 2015, 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.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.word.*; + +/** + * Jumps to the exception handler specified by {@link #address}. This node is specific for the + * {@link ExceptionHandlerStub} and should not be used elswhere. + */ +@NodeInfo +public final class JumpToExceptionHandlerNode extends FixedWithNextNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(JumpToExceptionHandlerNode.class); + @Input ValueNode address; + + public JumpToExceptionHandlerNode(ValueNode address) { + super(TYPE, StampFactory.forVoid()); + this.address = address; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + ((HotSpotNodeLIRBuilder) gen).emitJumpToExceptionHandler(address); + } + + @NodeIntrinsic + public static native void jumpToExceptionHandler(Word address); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2013, 2015, 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 static sun.misc.Version.*; - -import java.lang.invoke.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A call target that replaces itself in the graph when being lowered by restoring the original - * {@link MethodHandle} invocation target. Prior to - * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a - * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In - * that case, the original invocation must be restored with all of its original arguments. Why? - * HotSpot linkage for {@link MethodHandle} intrinsics (see - * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be - * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo* - * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} - * invocation drops these arguments which means the interpreter won't find them. - */ -@NodeInfo -public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable { - - public static final NodeClass TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class); - - /** - * Creates a call target for an invocation on a direct target derived by resolving a constant - * {@link MethodHandle}. - */ - public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, JavaType originalReturnType) { - if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) { - // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60 - return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType); - } - return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType); - } - - protected final ResolvedJavaMethod originalTargetMethod; - protected final JavaType originalReturnType; - @Input NodeInputList originalArguments; - - protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, JavaType originalReturnType) { - super(TYPE, invokeKind, targetMethod, arguments, returnType); - this.originalTargetMethod = originalTargetMethod; - this.originalReturnType = originalReturnType; - this.originalArguments = new NodeInputList<>(this, originalArguments); - } - - @Override - public void lower(LoweringTool tool) { - InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special; - MethodCallTargetNode replacement = graph().add( - new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType)); - - // Replace myself... - this.replaceAndDelete(replacement); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - throw GraalInternalError.shouldNotReachHere("should have replaced itself"); - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,7 @@ import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -31,7 +31,7 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -32,7 +32,7 @@ import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/KlassPointerStamp.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -58,6 +58,11 @@ } @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding); + } + + @Override public boolean isCompatible(Stamp otherStamp) { if (this == otherStamp) { return true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MetaspacePointerStamp.java Thu May 28 17:44:05 2015 +0200 @@ -39,28 +39,6 @@ } @Override - public Stamp meet(Stamp other) { - assert isCompatible(other); - return this; - } - - @Override - public Stamp improveWith(Stamp other) { - return this; - } - - @Override - public Stamp join(Stamp other) { - assert isCompatible(other); - return this; - } - - @Override - public Stamp unrestricted() { - return this; - } - - @Override public Stamp empty() { // there is no empty pointer stamp return this; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MethodPointerStamp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MethodPointerStamp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/type/MethodPointerStamp.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -47,6 +47,18 @@ } @Override + protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) { + if (newNonNull) { + assert !newAlwaysNull; + return METHOD_NON_NULL; + } else if (newAlwaysNull) { + return METHOD_ALWAYS_NULL; + } else { + return METHOD; + } + } + + @Override public boolean isCompatible(Stamp otherStamp) { if (this == otherStamp) { return true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Thu May 28 17:44:05 2015 +0200 @@ -35,6 +35,7 @@ import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -26,10 +26,11 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -32,9 +32,10 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Thu May 28 17:44:05 2015 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; @@ -39,25 +38,8 @@ /** * Substitutions for {@link CRC32}. */ -@ClassSubstitution(value = CRC32.class, defaultGuard = CRC32Substitutions.Guard.class) public class CRC32Substitutions { - public static class Guard implements SubstitutionGuard { - - @SuppressWarnings("unused") private HotSpotVMConfig config; - - public Guard(HotSpotVMConfig config) { - this.config = config; - } - - public boolean execute() { - /* - * Disabled until MethodSubstitutions are compiled like snipppets. - */ - return false; // return config.useCRC32Intrinsics; - } - } - /** * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}. */ @@ -66,7 +48,6 @@ return runtime().getConfig().crcTableAddress; } - @MethodSubstitution(isStatic = true) static int update(int crc, int b) { int c = ~crc; int index = (b ^ c) & 0xFF; @@ -76,13 +57,11 @@ return ~result; } - @MethodSubstitution(isStatic = true) static int updateBytes(int crc, byte[] buf, int off, int len) { Word bufAddr = Word.unsigned(GetObjectAddressNode.get(buf) + arrayBaseOffset(Kind.Byte) + off); return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len); } - @MethodSubstitution(isStatic = true, optional = true) static int updateByteBuffer(int crc, long addr, int off, int len) { Word bufAddr = Word.unsigned(addr).add(off); return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -33,6 +33,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** @@ -75,7 +76,7 @@ } if (clazz instanceof GetClassNode) { GetClassNode getClass = (GetClassNode) clazz; - return new LoadHubNode(KlassPointerStamp.klass(), getClass.getObject(), null); + return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject(), null); } if (clazz instanceof HubGetClassNode) { // replace _klass._java_mirror._klass -> _klass diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java Thu May 28 17:44:05 2015 +0200 @@ -48,6 +48,7 @@ public static boolean isInterface(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (klass.isNull()) { + // Class for primitive type return false; } else { int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION); @@ -58,6 +59,7 @@ public static boolean isArray(final Class thisObj) { KlassPointer klass = ClassGetHubNode.readClass(thisObj); if (klass.isNull()) { + // Class for primitive type return false; } else { return klassIsArray(klass); @@ -85,6 +87,8 @@ } } } + } else { + // Class for primitive type } return null; } @@ -99,6 +103,8 @@ if (klassIsArray(klass)) { return PiNode.asNonNullClass(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR)); } + } else { + // Class for primitive type } return null; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Thu May 28 17:44:05 2015 +0200 @@ -825,6 +825,11 @@ public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = NamedLocationIdentity.immutable("ObjArrayKlass::_element_klass"); + @Fold + public static int arrayClassElementOffset() { + return config().arrayClassElementOffset; + } + public static final LocationIdentity PRIMARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("PrimarySupers"); public static final LocationIdentity METASPACE_ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("MetaspaceArrayLength"); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Thu May 28 17:44:05 2015 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import java.util.zip.*; - import sun.misc.*; import sun.reflect.*; @@ -43,7 +41,6 @@ replacements.registerSubstitutions(System.class, SystemSubstitutions.class); replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class); replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class); - replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2013, 2015, 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.replacements; - -import java.lang.invoke.*; -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.Assumptions.AssumptionResult; -import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Node for invocation methods defined on the class {@link MethodHandle}. - */ -@NodeInfo -public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable { - public static final NodeClass TYPE = NodeClass.create(MethodHandleNode.class); - - protected final IntrinsicMethod intrinsicMethod; - - public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { - super(TYPE, invokeKind, targetMethod, bci, returnType, arguments); - this.intrinsicMethod = intrinsicMethod; - } - - /** - * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an - * invocation on another method with possibly transformed arguments. - * - * @param assumptions object for recording any speculations made during the transformation - * @param methodHandleAccess objects for accessing the implementation internals of a - * {@link MethodHandle} - * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed - * @param bci the BCI of the original {@link MethodHandle} call - * @param returnType return type of the original {@link MethodHandle} call - * @param arguments arguments to the original {@link MethodHandle} call - * @return a more direct invocation derived from the {@link MethodHandle} call or null - */ - public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode... arguments) { - switch (intrinsicMethod) { - case INVOKE_BASIC: - return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); - case LINK_TO_STATIC: - case LINK_TO_SPECIAL: - case LINK_TO_VIRTUAL: - case LINK_TO_INTERFACE: - return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void simplify(SimplifierTool tool) { - MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess(); - ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]); - InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray); - if (invoke != null) { - assert invoke.graph() == null; - invoke = graph().addOrUniqueWithInputs(invoke); - invoke.setStateAfter(stateAfter()); - FixedNode currentNext = next(); - replaceAtUsages(invoke); - GraphUtil.removeFixedWithUnusedInputs(this); - graph().addBeforeFixed(currentNext, invoke); - } - } - - /** - * Get the receiver of a MethodHandle.invokeBasic call. - * - * @return the receiver argument node - */ - private static ValueNode getReceiver(ValueNode[] arguments) { - return arguments[0]; - } - - /** - * Get the MemberName argument of a MethodHandle.linkTo* call. - * - * @return the MemberName argument node (which is the last argument) - */ - private static ValueNode getMemberName(ValueNode[] arguments) { - return arguments[arguments.length - 1]; - } - - /** - * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC } - * method) to get the target {@link InvokeNode} if the method handle receiver is constant. - * - * @return invoke node for the {@link java.lang.invoke.MethodHandle} target - */ - private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode[] arguments) { - ValueNode methodHandleNode = getReceiver(arguments); - if (methodHandleNode.isConstant()) { - return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original); - } - return null; - } - - /** - * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC}, - * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and - * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if - * the member name argument is constant. - * - * @return invoke node for the member name target - */ - private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode[] arguments) { - ValueNode memberNameNode = getMemberName(arguments); - if (memberNameNode.isConstant()) { - return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original); - } - return null; - } - - /** - * Helper function to get the {@link InvokeNode} for the targetMethod of a - * java.lang.invoke.MemberName. - * - * @param target the target, already loaded from the member name node - * @return invoke node for the member name target - */ - private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target, - ResolvedJavaMethod original) { - if (target == null) { - return null; - } - - // In lambda forms we erase signature types to avoid resolving issues - // involving class loaders. When we optimize a method handle invoke - // to a direct call we must cast the receiver and arguments to its - // actual types. - Signature signature = target.getSignature(); - final boolean isStatic = target.isStatic(); - final int receiverSkip = isStatic ? 0 : 1; - - // Cast receiver to its type. - if (!isStatic) { - JavaType receiverType = target.getDeclaringClass(); - maybeCastArgument(arguments, 0, receiverType); - } - - // Cast reference arguments to its type. - for (int index = 0; index < signature.getParameterCount(false); index++) { - JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass()); - maybeCastArgument(arguments, receiverSkip + index, parameterType); - } - - if (target.canBeStaticallyBound()) { - return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments); - } - - // Try to get the most accurate receiver type - if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) { - ValueNode receiver = getReceiver(arguments); - ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp()); - if (receiverType != null) { - AssumptionResult concreteMethod = receiverType.findUniqueConcreteMethod(target); - if (concreteMethod != null) { - assumptions.record(concreteMethod); - return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); - } - } - } else { - AssumptionResult concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target); - if (concreteMethod != null) { - assumptions.record(concreteMethod); - return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); - } - } - - return null; - } - - /** - * Inserts a node to cast the argument at index to the given type if the given type is more - * concrete than the argument type. - * - * @param index of the argument to be cast - * @param type the type the argument should be cast to - */ - private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) { - if (type instanceof ResolvedJavaType) { - ResolvedJavaType targetType = (ResolvedJavaType) type; - if (!targetType.isPrimitive()) { - ValueNode argument = arguments[index]; - ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp()); - if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) { - PiNode piNode = new PiNode(argument, StampFactory.declared(targetType)); - arguments[index] = piNode; - } - } - } - } - - /** - * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed - * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}. - * - * @return invoke node for the member name target - */ - private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) { - InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special; - JavaType targetReturnType = target.getSignature().getReturnType(null); - - // MethodHandleLinkTo* nodes have a trailing MemberName argument which - // needs to be popped. - ValueNode[] targetArguments; - switch (intrinsicMethod) { - case INVOKE_BASIC: - targetArguments = arguments; - break; - case LINK_TO_STATIC: - case LINK_TO_SPECIAL: - case LINK_TO_VIRTUAL: - case LINK_TO_INTERFACE: - targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - - MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType); - - // The call target can have a different return type than the invoker, - // e.g. the target returns an Object but the invoker void. In this case - // we need to use the stamp of the invoker. Note: always using the - // invoker's stamp would be wrong because it's a less concrete type - // (usually java.lang.Object). - if (returnType.getKind() == Kind.Void) { - return new InvokeNode(callTarget, bci, StampFactory.forVoid()); - } else { - return new InvokeNode(callTarget, bci); - } - } -} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu May 28 17:44:05 2015 +0200 @@ -157,8 +157,7 @@ public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub); @Snippet - public static Object allocateInstanceDynamic(Class type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, - @SuppressWarnings("unused") @ConstantParameter String typeContext) { + public static Object allocateInstanceDynamic(Class type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { KlassPointer hub = ClassGetHubNode.readClass(type); if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) { if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) { @@ -202,13 +201,13 @@ Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(allocationSize); - if ((skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && + probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); newarray_loopInit.inc(); result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true); } else { - newarray_stub.inc(); result = newArray(HotSpotBackend.NEW_ARRAY, hub, length); } profileAllocation("array", allocationSize, typeContext); @@ -234,7 +233,7 @@ @Snippet public static Object allocateArrayDynamic(Class elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { Word hub = loadWordFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION); - if (hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH))) { return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu May 28 17:44:05 2015 +0200 @@ -56,14 +56,14 @@ final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(method); final Replacements replacements = tool.getReplacements(); StructuredGraph snippetGraph = null; - try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) { + try (Scope s = Debug.scope("ArrayCloneSnippet", snippetMethod)) { snippetGraph = replacements.getSnippet(snippetMethod, null); } catch (Throwable e) { throw Debug.handle(e); } assert snippetGraph != null : "ObjectCloneSnippets should be installed"; - return lowerReplacement(snippetGraph.copy(), tool); + return lowerReplacement((StructuredGraph) snippetGraph.copy(), tool); } assert false : "unhandled array type " + type.getComponentType().getKind(); } else { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeLoadSnippets.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -27,8 +27,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Thu May 28 17:44:05 2015 +0200 @@ -38,8 +38,8 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -23,12 +23,11 @@ //JaCoCo Exclude package com.oracle.graal.hotspot.replacements.arraycopy; -import static com.oracle.graal.api.meta.LocationIdentity.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -36,20 +35,24 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.runtime.*; @NodeInfo(allowedUsageTypes = {InputType.Memory}) -public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { +public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, MemoryAccess, Canonicalizable { public static final NodeClass TYPE = NodeClass.create(ArrayCopyCallNode.class); - @Input ValueNode src; - @Input ValueNode srcPos; - @Input ValueNode dest; - @Input ValueNode destPos; - @Input ValueNode length; + @Input protected ValueNode src; + @Input protected ValueNode srcPos; + @Input protected ValueNode dest; + @Input protected ValueNode destPos; + @Input protected ValueNode length; - protected Kind elementKind; + @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; + + protected final Kind elementKind; + protected final LocationIdentity locationIdentity; /** * Aligned means that the offset of the copy is heap word aligned. @@ -62,16 +65,16 @@ public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized) { - this(src, srcPos, dest, destPos, length, elementKind, aligned, disjoint, uninitialized, runtime); + this(runtime, src, srcPos, dest, destPos, length, elementKind, null, aligned, disjoint, uninitialized); } public ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean disjoint) { - this(src, srcPos, dest, destPos, length, elementKind, false, disjoint, false, runtime); + this(runtime, src, srcPos, dest, destPos, length, elementKind, null, false, disjoint, false); } - protected ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized, - HotSpotGraalRuntimeProvider runtime) { + protected ArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, + LocationIdentity locationIdentity, boolean aligned, boolean disjoint, boolean uninitialized) { super(TYPE, StampFactory.forVoid()); assert elementKind != null; this.src = src; @@ -80,6 +83,7 @@ this.destPos = destPos; this.length = length; this.elementKind = elementKind; + this.locationIdentity = (locationIdentity != null ? locationIdentity : NamedLocationIdentity.getArrayLocation(elementKind)); this.aligned = aligned; this.disjoint = disjoint; this.uninitialized = uninitialized; @@ -121,7 +125,8 @@ public void lower(LoweringTool tool) { if (graph().getGuardsStage().areFrameStatesAtDeopts()) { updateAlignedDisjoint(); - ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized()); + ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupArraycopyDescriptor(elementKind, isAligned(), isDisjoint(), isUninitialized(), + locationIdentity.equals(LocationIdentity.any())); StructuredGraph graph = graph(); ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); @@ -132,24 +137,38 @@ ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len)); call.setStateAfter(stateAfter()); graph.replaceFixedWithFixed(this, call); + } + } - } + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; } @Override public LocationIdentity getLocationIdentity() { - if (elementKind != null) { - return NamedLocationIdentity.getArrayLocation(elementKind); - } - return any(); + return locationIdentity; } @NodeIntrinsic private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized); - public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, boolean aligned, boolean disjoint) { - arraycopy(src, srcPos, dest, destPos, length, elementKind, aligned, disjoint, false); + @NodeIntrinsic + private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind, + @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter boolean aligned, @ConstantNodeParameter boolean disjoint, + @ConstantNodeParameter boolean uninitialized); + + public static void arraycopyObjectKillsAny(Object src, int srcPos, Object dest, int destPos, int length) { + arraycopy(src, srcPos, dest, destPos, length, Kind.Object, LocationIdentity.any(), false, false, false); + } + + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) { + arraycopy(src, srcPos, dest, destPos, length, elementKind, false, false, false); } public static void disjointArraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind) { @@ -194,4 +213,15 @@ } } } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (getLength().isConstant() && getLength().asConstant().isDefaultForKind()) { + if (lastLocationAccess != null) { + replaceAtUsages(InputType.Memory, lastLocationAccess.asNode()); + } + return null; + } + return this; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java Thu May 28 17:44:05 2015 +0200 @@ -22,19 +22,13 @@ */ package com.oracle.graal.hotspot.replacements.arraycopy; +import static com.oracle.graal.api.meta.LocationIdentity.*; + import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; -import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.nodes.*; @NodeInfo @@ -42,101 +36,26 @@ public static final NodeClass TYPE = NodeClass.create(ArrayCopyNode.class); - public ArrayCopyNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { - super(TYPE, invokeKind, targetMethod, bci, returnType, src, srcPos, dst, dstPos, length); - } - - private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) { - ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp()); - ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp()); + private Kind elementKind; - if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { - return null; - } - if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { - return null; - } - if (!isExact()) { - return null; - } - Kind componentKind = srcType.getComponentType().getKind(); - final ResolvedJavaMethod snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind, shouldUnroll(), isExact())); - try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) { - return replacements.getSnippet(snippetMethod, null, null); - } catch (Throwable e) { - throw Debug.handle(e); - } - } - - private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { - ParameterNode lengthParam = snippetGraph.getParameter(4); - if (lengthParam != null) { - snippetGraph.replaceFloating(lengthParam, ConstantNode.forInt(length, snippetGraph)); - } - // the canonicalization before loop unrolling is needed to propagate the length into - // additions, etc. - PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider()); - new CanonicalizerPhase().apply(snippetGraph, context); - new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(snippetGraph, context); - new CanonicalizerPhase().apply(snippetGraph, context); + public ArrayCopyNode(int bci, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) { + super(TYPE, src, srcPos, dst, dstPos, length, null, bci); + elementKind = ArrayCopySnippets.Templates.selectComponentKind(this); } @Override - protected StructuredGraph getLoweredSnippetGraph(final LoweringTool tool) { - final Replacements replacements = tool.getReplacements(); - StructuredGraph snippetGraph = selectSnippet(tool, replacements); - if (snippetGraph == null) { - ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp()); - ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp()); - ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType(); - ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType(); - ResolvedJavaMethod snippetMethod = null; - if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) { - snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.checkcastArraycopySnippet); - } else { - snippetMethod = tool.getMetaAccess().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); - } - snippetGraph = null; - try (Scope s = Debug.scope("ArrayCopySnippet", snippetMethod)) { - snippetGraph = replacements.getSnippet(snippetMethod, getTargetMethod(), null).copy(); - } catch (Throwable e) { - throw Debug.handle(e); - } - replaceSnippetInvokes(snippetGraph); - } else { - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - snippetGraph = snippetGraph.copy(); - if (shouldUnroll()) { - final StructuredGraph copy = snippetGraph; - try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) { - unrollFixedLengthLoop(copy, getLength().asJavaConstant().asInt(), tool); - } catch (Throwable e) { - throw Debug.handle(e); - } - } + public LocationIdentity getLocationIdentity() { + if (elementKind == null) { + elementKind = ArrayCopySnippets.Templates.selectComponentKind(this); } - return lowerReplacement(snippetGraph, tool); + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); } - private boolean shouldUnroll() { - return getLength().isConstant() && getLength().asJavaConstant().asInt() <= GraalOptions.MaximumEscapeAnalysisArrayLength.getValue(); - } - - /* - * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. - */ - private boolean isExact() { - ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp()); - if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) { - return true; - } - - ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp()); - if (StampTool.isExactType(getDestination().stamp())) { - if (destType != null && destType.isAssignableFrom(srcType)) { - return true; - } - } - return false; + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.replacements.arraycopy; + +import static com.oracle.graal.api.meta.LocationIdentity.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +@NodeInfo +public final class ArrayCopySlowPathNode extends BasicArrayCopyNode { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopySlowPathNode.class); + + private final SnippetTemplate.SnippetInfo snippet; + + public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, SnippetTemplate.SnippetInfo snippet) { + super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI); + assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked"; + this.snippet = snippet; + } + + @NodeIntrinsic + public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter Kind elementKind, + @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet); + + public SnippetTemplate.SnippetInfo getSnippet() { + return snippet; + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + public void setBci(int bci) { + this.bci = bci; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -30,74 +30,33 @@ import java.lang.reflect.*; import java.util.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.type.*; import com.oracle.graal.hotspot.word.*; +import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; public class ArrayCopySnippets implements Snippets { - private static final EnumMap arraycopyMethods = new EnumMap<>(Kind.class); - private static final EnumMap arraycopyCalls = new EnumMap<>(Kind.class); - - public static final Method checkcastArraycopySnippet; - public static final Method genericArraycopySnippet; - - private static void addArraycopySnippetMethod(Kind kind, Class arrayClass) throws NoSuchMethodException { - arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); - if (CallArrayCopy.getValue()) { - if (kind == Kind.Object) { - arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod("objectArraycopyUnchecked", arrayClass, int.class, arrayClass, int.class, int.class)); - } else { - arraycopyCalls.put(kind, ArrayCopySnippets.class.getDeclaredMethod(kind + "Arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); - } - } - } - - static { - try { - addArraycopySnippetMethod(Kind.Byte, byte[].class); - addArraycopySnippetMethod(Kind.Boolean, boolean[].class); - addArraycopySnippetMethod(Kind.Char, char[].class); - addArraycopySnippetMethod(Kind.Short, short[].class); - addArraycopySnippetMethod(Kind.Int, int[].class); - addArraycopySnippetMethod(Kind.Long, long[].class); - addArraycopySnippetMethod(Kind.Float, float[].class); - addArraycopySnippetMethod(Kind.Double, double[].class); - addArraycopySnippetMethod(Kind.Object, Object[].class); - checkcastArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("checkcastArraycopy", Object[].class, int.class, Object[].class, int.class, int.class); - genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); - } catch (SecurityException | NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - - public static Method getSnippetForKind(Kind kind, boolean shouldUnroll, boolean exact) { - Method m = null; - if (!shouldUnroll && exact) { - // use hotspot stubs - m = arraycopyCalls.get(kind); - if (m != null) { - return m; - } - } - // use snippets - return arraycopyMethods.get(kind); - } - - private static void checkedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { - Object nonNullSrc = guardingNonNull(src); - Object nonNullDest = guardingNonNull(dest); - checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); - UnsafeArrayCopyNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, baseKind); - } - private static int checkArrayType(KlassPointer hub) { int layoutHelper = readLayoutHelper(hub); if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) { @@ -131,90 +90,119 @@ } @Snippet - public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { - byteCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Byte); - } - - @Snippet - public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { - booleanCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Boolean); - } - - @Snippet - public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { - charCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Char); - } - - @Snippet - public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { - shortCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Short); - } - - @Snippet - public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { - intCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Int); - } - - @Snippet - public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { - floatCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Float); + public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length) { + Object nonNullSrc = guardingNonNull(src); + Object nonNullDest = guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + checkArrayType(srcHub); + checkArrayType(destHub); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + zeroLengthStaticCounter.inc(); } @Snippet - public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { - longCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Long); - } - - @Snippet - public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { - doubleCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Double); - } - - @Snippet - public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { - objectCounter.inc(); - checkedCopy(src, srcPos, dest, destPos, length, Kind.Object); - } - - @Snippet - public static void checkcastArraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { - objectCheckcastCounter.inc(); + public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetCounter counter) { Object nonNullSrc = guardingNonNull(src); Object nonNullDest = guardingNonNull(dest); checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); - if (probability(SLOW_PATH_PROBABILITY, nonNullSrc == nonNullDest)) { - // no storecheck required. - ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object, false, false); + counter.inc(); + ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind); + if (length == 0) { + zeroLengthDynamicCounter.inc(); } else { - KlassPointer destElemKlass = loadHub(nonNullDest); - checkcastArraycopyHelper(srcPos, destPos, length, nonNullSrc, nonNullDest, destElemKlass); + nonZeroLengthDynamicCounter.inc(); } } - private static void checkcastArraycopyHelper(int srcPos, int destPos, int length, Object nonNullSrc, Object nonNullDest, KlassPointer destElemKlass) { - Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(), KLASS_SUPER_CHECK_OFFSET_LOCATION)); - int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false); - if (copiedElements != 0) { - // the checkcast stub doesn't throw the ArrayStoreException, but returns the number of - // copied elements (xor'd with -1). - copiedElements ^= -1; - System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements); + /** + * This intrinsic is useful for the case where we know something statically about one of the + * inputs but not the other. + */ + @Snippet + public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetCounter counter) { + Object nonNullSrc = guardingNonNull(src); + Object nonNullDest = guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + counter.inc(); + ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind); + if (length == 0) { + zeroLengthDynamicCounter.inc(); } else { - // Capture an after state for this path. - ArrayCopyStateNode.captureState(); + nonZeroLengthDynamicCounter.inc(); } } @Snippet - public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass, @ConstantParameter SnippetCounter counter) { + if (length > 0) { + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) { + counter.inc(); + predictedObjectArrayCopyFastPathCounter.inc(); + ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length); + } else { + predictedObjectArrayCopySlowPathCounter.inc(); + System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length); + } + } + } + + /** + * This is the basic template for the full arraycopy checks, including a check that the + * underlying type is really an array type. + */ + @Snippet + public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Kind elementKind, @ConstantParameter SnippetInfo slowPath) { + Object nonNullSrc = guardingNonNull(src); + Object nonNullDest = guardingNonNull(dest); + KlassPointer srcHub = loadHub(nonNullSrc); + KlassPointer destHub = loadHub(nonNullDest); + checkArrayType(srcHub); + checkArrayType(destHub); + checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); + if (length == 0) { + zeroLengthDynamicCounter.inc(); + } else { + nonZeroLengthDynamicCounter.inc(); + } + ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind, slowPath); + } + + @Snippet + public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length) { + if (length > 0) { + KlassPointer destKlass = loadHub(nonNullDest); + KlassPointer srcKlass = loadHub(nonNullSrc); + if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) { + // no storecheck required. + objectCheckcastSameTypeCounter.inc(); + ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length); + } else { + KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION); + Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(), KLASS_SUPER_CHECK_OFFSET_LOCATION)); + objectCheckcastCounter.inc(); + int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false); + if (copiedElements != 0) { + /* + * the checkcast stub doesn't throw the ArrayStoreException, but returns the + * number of copied elements (xor'd with -1). + */ + copiedElements ^= -1; + System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements); + } + } + } + } + + @Snippet + public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length) { Object nonNullSrc = guardingNonNull(src); Object nonNullDest = guardingNonNull(dest); KlassPointer srcHub = loadHub(nonNullSrc); @@ -225,102 +213,326 @@ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); if (probability(FAST_PATH_PROBABILITY, isObjectArray)) { genericObjectExactCallCounter.inc(); - UnsafeArrayCopyNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object); + ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, Kind.Object); } else { genericPrimitiveCallCounter.inc(); UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper); } } else { - genericObjectCallCounter.inc(); + SystemArraycopyCounter.inc(); System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length); } } - @NodeIntrinsic(ForeignCallNode.class) - public static native void callArraycopy(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word src, Word dest, Word len); - - private static void callArraycopyTemplate(SnippetCounter counter, Kind kind, boolean aligned, boolean disjoint, Object src, int srcPos, Object dest, int destPos, int length) { - counter.inc(); - Object nonNullSrc = guardingNonNull(src); - Object nonNullDest = guardingNonNull(dest); - checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length); - ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, kind, aligned, disjoint); - } - - @Snippet - public static void objectArraycopyUnchecked(Object[] src, int srcPos, Object[] dest, int destPos, int length) { - callArraycopyTemplate(objectCallCounter, Kind.Object, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void byteArraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { - callArraycopyTemplate(byteCallCounter, Kind.Byte, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void booleanArraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { - callArraycopyTemplate(booleanCallCounter, Kind.Boolean, false, false, src, srcPos, dest, destPos, length); + @Fold + private static LocationIdentity getArrayLocation(Kind kind) { + return NamedLocationIdentity.getArrayLocation(kind); } @Snippet - public static void charArraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { - callArraycopyTemplate(charCallCounter, Kind.Char, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void shortArraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { - callArraycopyTemplate(shortCallCounter, Kind.Short, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void intArraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { - callArraycopyTemplate(intCallCounter, Kind.Int, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void floatArraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { - callArraycopyTemplate(floatCallCounter, Kind.Float, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void longArraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { - callArraycopyTemplate(longCallCounter, Kind.Long, false, false, src, srcPos, dest, destPos, length); - } - - @Snippet - public static void doubleArraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { - callArraycopyTemplate(doubleCallCounter, Kind.Double, false, false, src, srcPos, dest, destPos, length); + public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter Kind elementKind) { + final int scale = arrayIndexScale(elementKind); + int arrayBaseOffset = arrayBaseOffset(elementKind); + LocationIdentity arrayLocation = getArrayLocation(elementKind); + if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + long i = start; + ExplodeLoopNode.explodeLoop(); + for (int iteration = 0; iteration < length; iteration++) { + if (i >= 0) { + Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation); + DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind); + i -= scale; + } + } + } else { + long end = (long) length * scale; + long i = 0; + ExplodeLoopNode.explodeLoop(); + for (int iteration = 0; iteration < length; iteration++) { + if (i < end) { + Object a = UnsafeLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation); + DirectObjectStoreNode.storeObject(nonNullDest, arrayBaseOffset, i + (long) destPos * scale, a, arrayLocation, elementKind); + i += scale; + } + } + } } private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); - private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE"); private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE"); private static final SnippetCounter.Group counters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy") : null; - private static final SnippetCounter byteCounter = new SnippetCounter(counters, "byte[]", "arraycopy for byte[] arrays"); - private static final SnippetCounter charCounter = new SnippetCounter(counters, "char[]", "arraycopy for char[] arrays"); - private static final SnippetCounter shortCounter = new SnippetCounter(counters, "short[]", "arraycopy for short[] arrays"); - private static final SnippetCounter intCounter = new SnippetCounter(counters, "int[]", "arraycopy for int[] arrays"); - private static final SnippetCounter booleanCounter = new SnippetCounter(counters, "boolean[]", "arraycopy for boolean[] arrays"); - private static final SnippetCounter longCounter = new SnippetCounter(counters, "long[]", "arraycopy for long[] arrays"); - private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); + private static final SnippetCounter objectCheckcastCounter = new SnippetCounter(counters, "Object[]", "arraycopy for non-exact Object[] arrays"); - private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); - private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); + private static final SnippetCounter objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]", "arraycopy call for src.klass == dest.klass Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]", "used System.arraycopy slow path for predicted Object[] arrays"); + private static final SnippetCounter predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]", "used oop_arraycopy for predicted Object[] arrays"); + + private static final EnumMap arraycopyCallCounters = new EnumMap<>(Kind.class); + private static final EnumMap arraycopyCounters = new EnumMap<>(Kind.class); - private static final SnippetCounter objectCallCounter = new SnippetCounter(counters, "Object[]", "arraycopy call for Object[] arrays"); + static void createArraycopyCounter(Kind kind) { + arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]", "arraycopy call for " + kind + "[] arrays")); + arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]", "inline arraycopy for " + kind + "[] arrays")); + } - private static final SnippetCounter booleanCallCounter = new SnippetCounter(counters, "boolean[]", "arraycopy call for boolean[] arrays"); - private static final SnippetCounter byteCallCounter = new SnippetCounter(counters, "byte[]", "arraycopy call for byte[] arrays"); - private static final SnippetCounter charCallCounter = new SnippetCounter(counters, "char[]", "arraycopy call for char[] arrays"); - private static final SnippetCounter doubleCallCounter = new SnippetCounter(counters, "double[]", "arraycopy call for double[] arrays"); - private static final SnippetCounter floatCallCounter = new SnippetCounter(counters, "float[]", "arraycopy call for float[] arrays"); - private static final SnippetCounter intCallCounter = new SnippetCounter(counters, "int[]", "arraycopy call for int[] arrays"); - private static final SnippetCounter longCallCounter = new SnippetCounter(counters, "long[]", "arraycopy call for long[] arrays"); - private static final SnippetCounter shortCallCounter = new SnippetCounter(counters, "short[]", "arraycopy call for short[] arrays"); + static { + createArraycopyCounter(Kind.Byte); + createArraycopyCounter(Kind.Boolean); + createArraycopyCounter(Kind.Char); + createArraycopyCounter(Kind.Short); + createArraycopyCounter(Kind.Int); + createArraycopyCounter(Kind.Long); + createArraycopyCounter(Kind.Float); + createArraycopyCounter(Kind.Double); + createArraycopyCounter(Kind.Object); + } private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); - private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); + private static final SnippetCounter SystemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy"); + + private static final SnippetCounter.Group lengthCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy 0-length checks") : null; + + private static final SnippetCounter zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0"); + private static final SnippetCounter zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0"); + private static final SnippetCounter nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero"); + + public static class Templates extends SnippetTemplate.AbstractTemplates { + + public Templates(HotSpotProviders providers, TargetDescription target) { + super(providers, providers.getSnippetReflection(), target); + } + + private ResolvedJavaMethod originalArraycopy() throws GraalInternalError { + if (originalArraycopy == null) { + Method method; + try { + method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method); + } + return originalArraycopy; + } + + private ResolvedJavaMethod originalArraycopy; + + private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork"); + private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric"); + + private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic"); + private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic"); + private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic"); + private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic"); + private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork"); + + private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork"); + + protected SnippetInfo snippet(String methodName) { + SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any()); + info.setOriginalMethod(originalArraycopy()); + return info; + } + + public static Kind selectComponentKind(BasicArrayCopyNode arraycopy) { + return selectComponentKind(arraycopy, true); + } + + public static Kind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) { + ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp()); + ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp()); + + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + if (!exact) { + Kind component = getComponentKind(srcType); + if (component != null) { + return component; + } + return getComponentKind(destType); + } + return null; + } + if (exact) { + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) { + return null; + } + if (!arraycopy.isExact()) { + return null; + } + } + return srcType.getComponentType().getKind(); + } + + private static Kind getComponentKind(ResolvedJavaType type) { + if (type != null && type.isArray()) { + return type.getComponentType().getKind(); + } + return null; + } + + private static boolean shouldUnroll(ValueNode length) { + return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0; + } + + private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { + ParameterNode lengthParam = snippetGraph.getParameter(4); + if (lengthParam != null) { + snippetGraph.replaceFloating(lengthParam, ConstantNode.forInt(length, snippetGraph)); + } + // the canonicalization before loop unrolling is needed to propagate the length into + // additions, etc. + PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider()); + new CanonicalizerPhase().apply(snippetGraph, context); + new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(snippetGraph, context); + new CanonicalizerPhase().apply(snippetGraph, context); + } + + void unrollSnippet(final LoweringTool tool, StructuredGraph snippetGraph, ArrayCopyNode arraycopy) { + if (shouldUnroll(arraycopy.getLength())) { + final StructuredGraph copy = snippetGraph; + try (Scope s = Debug.scope("ArrayCopySnippetSpecialization", snippetGraph.method())) { + unrollFixedLengthLoop(copy, arraycopy.getLength().asJavaConstant().asInt(), tool); + } catch (Throwable e) { + throw Debug.handle(e); + } + } + } + + public void lower(ArrayCopyNode arraycopy, LoweringTool tool) { + Kind componentKind = selectComponentKind(arraycopy); + SnippetInfo snippetInfo = null; + SnippetInfo slowPathSnippetInfo = null; + + if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) { + snippetInfo = arraycopyZeroLengthIntrinsicSnippet; + } else if (arraycopy.isExact()) { + snippetInfo = arraycopyExactIntrinsicSnippet; + if (shouldUnroll(arraycopy.getLength())) { + snippetInfo = arraycopySlowPathIntrinsicSnippet; + slowPathSnippetInfo = arraycopyUnrolledWorkSnippet; + } + } else { + if (componentKind == Kind.Object) { + ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp()); + ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp()); + ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType(); + ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType(); + if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) { + snippetInfo = arraycopySlowPathIntrinsicSnippet; + slowPathSnippetInfo = checkcastArraycopyWorkSnippet; + /* + * Because this snippet has to use Sysytem.arraycopy as a slow path, we must + * pretend to kill any() so clear the componentKind. + */ + componentKind = null; + } + } + if (componentKind == null && snippetInfo == null) { + Kind predictedKind = selectComponentKind(arraycopy, false); + if (predictedKind != null) { + /* + * At least one array is of a known type requiring no store checks, so + * assume the other is of the same type. Generally this is working around + * deficiencies in our propation of type information. + */ + componentKind = predictedKind; + if (predictedKind == Kind.Object) { + snippetInfo = arraycopySlowPathIntrinsicSnippet; + slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet; + componentKind = null; + } else { + snippetInfo = arraycopyPredictedExactIntrinsicSnippet; + } + } + } + if (snippetInfo == null) { + snippetInfo = arraycopyGenericSnippet; + } + } + Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("src", arraycopy.getSource()); + args.add("srcPos", arraycopy.getSourcePosition()); + args.add("dest", arraycopy.getDestination()); + args.add("destPos", arraycopy.getDestinationPosition()); + args.add("length", arraycopy.getLength()); + if (snippetInfo == arraycopySlowPathIntrinsicSnippet) { + args.addConst("elementKind", componentKind != null ? componentKind : Kind.Illegal); + args.addConst("slowPath", slowPathSnippetInfo); + } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) { + assert componentKind != null; + args.addConst("elementKind", componentKind); + args.addConst("counter", arraycopyCallCounters.get(componentKind)); + } + instantiate(args, arraycopy); + } + + public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) { + StructuredGraph graph = arraycopy.graph(); + if (!graph.getGuardsStage().areFrameStatesAtDeopts()) { + // Can't be lowered yet + return; + } + SnippetInfo snippetInfo = arraycopy.getSnippet(); + Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage()); + args.add("nonNullSrc", arraycopy.getSource()); + args.add("srcPos", arraycopy.getSourcePosition()); + args.add("nonNullDest", arraycopy.getDestination()); + args.add("destPos", arraycopy.getDestinationPosition()); + if (snippetInfo == arraycopyUnrolledWorkSnippet) { + args.addConst("length", arraycopy.getLength().asJavaConstant().asInt()); + args.addConst("elementKind", arraycopy.getElementKind()); + } else { + args.add("length", arraycopy.getLength()); + } + if (snippetInfo == arraycopyPredictedObjectWorkSnippet) { + HotSpotResolvedObjectType arrayKlass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class); + ValueNode objectArrayKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayKlass.klass(), tool.getMetaAccess(), arraycopy.graph()); + args.add("objectArrayKlass", objectArrayKlass); + args.addConst("counter", arraycopyCallCounters.get(Kind.Object)); + } + instantiate(args, arraycopy); + } + + /** + * Instantiate the snippet template and fix up the FrameState of any Invokes of + * System.arraycopy and propagate the captured bci in the ArrayCopySlowPathNode. + * + * @param args + * @param arraycopy + */ + private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { + StructuredGraph graph = arraycopy.graph(); + SnippetTemplate template = template(args); + Map replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args); + for (Node originalNode : replacements.keySet()) { + if (originalNode instanceof Invoke) { + Invoke invoke = (Invoke) replacements.get(originalNode); + assert invoke.asNode().graph() == graph; + CallTargetNode call = invoke.callTarget(); + + if (!call.targetMethod().equals(originalArraycopy)) { + throw new GraalInternalError("unexpected invoke %s in snippet", call.targetMethod()); + } + // Here we need to fix the bci of the invoke + InvokeNode newInvoke = graph.add(new InvokeNode(invoke.callTarget(), arraycopy.getBci())); + if (arraycopy.stateDuring() != null) { + newInvoke.setStateDuring(arraycopy.stateDuring()); + } else { + assert arraycopy.stateAfter() != null; + newInvoke.setStateAfter(arraycopy.stateAfter()); + } + graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); + } else if (originalNode instanceof ArrayCopySlowPathNode) { + ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode); + assert arraycopy.stateAfter() != null; + slowPath.setStateAfter(arraycopy.stateAfter()); + slowPath.setBci(arraycopy.getBci()); + } + } + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyStateNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyStateNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ -//JaCoCo Exclude -package com.oracle.graal.hotspot.replacements.arraycopy; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A dummy node whose only purpose is to capture a final {@link FrameState} when lowering complex - * arraycopy snippets. - */ - -@NodeInfo -public final class ArrayCopyStateNode extends AbstractStateSplit implements Lowerable { - - public static final NodeClass TYPE = NodeClass.create(ArrayCopyStateNode.class); - - protected ArrayCopyStateNode() { - super(TYPE, StampFactory.forKind(Kind.Void)); - - } - - @Override - public void lower(LoweringTool tool) { - if (graph().getGuardsStage().areFrameStatesAtDeopts()) { - graph().removeFixed(this); - } - } - - @NodeIntrinsic - public static native void captureState(); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -24,7 +24,6 @@ package com.oracle.graal.hotspot.replacements.arraycopy; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; @@ -34,8 +33,8 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.runtime.*; import com.oracle.graal.word.*; @NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}) @@ -107,11 +106,10 @@ ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); ValueNode len = getLength(); - if (len.stamp().getStackKind() != Kind.Long) { - len = IntegerConvertNode.convert(len, StampFactory.forKind(Kind.Long), graph()); + if (len.stamp().getStackKind() != runtime.getTarget().wordKind) { + len = IntegerConvertNode.convert(len, StampFactory.forKind(runtime.getTarget().wordKind), graph()); } - ForeignCallNode call = graph.add(new ForeignCallNode(Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, - destElemKlass)); + ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, destElemKlass)); call.setStateAfter(stateAfter()); graph.replaceFixedWithFixed(this, call); } @@ -119,7 +117,11 @@ @Override public LocationIdentity getLocationIdentity() { - return NamedLocationIdentity.getArrayLocation(Kind.Object); + /* + * Because of restrictions that the memory graph of snippets matches the original node, + * pretend that we kill any. + */ + return LocationIdentity.any(); } @NodeIntrinsic diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Thu May 28 17:44:05 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.SnippetTemplate.Arguments; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerNode.*; import static com.oracle.graal.hotspot.nodes.PatchReturnAddressNode.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.stubs.StubUtil.*; @@ -32,7 +33,6 @@ 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.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.replacements.*; @@ -40,10 +40,10 @@ import com.oracle.graal.word.*; /** - * Stub called by the {@linkplain MarkId#EXCEPTION_HANDLER_ENTRY exception handler entry point} in a - * compiled method. This entry point is used when returning to a method to handle an exception - * thrown by a callee. It is not used for routing implicit exceptions. Therefore, it does not need - * to save any registers as HotSpot uses a caller save convention. + * Stub called by the {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler + * entry point} in a compiled method. This entry point is used when returning to a method to handle + * an exception thrown by a callee. It is not used for routing implicit exceptions. Therefore, it + * does not need to save any registers as HotSpot uses a caller save convention. *

    * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}. */ @@ -96,7 +96,7 @@ } // patch the return address so that this stub returns to the exception handler - patchReturnAddress(handlerPc); + jumpToExceptionHandler(handlerPc); } static void checkNoExceptionInThread(Word thread, boolean enabled) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Thu May 28 17:44:05 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; + import java.lang.reflect.*; import com.oracle.graal.api.meta.*; @@ -94,8 +96,8 @@ assert SnippetGraphUnderConstruction.get() == null; SnippetGraphUnderConstruction.set(graph); - ReplacementContext initialReplacementContext = new ReplacementContext(method, method); - new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); + IntrinsicContext initialIntrinsicContext = new IntrinsicContext(method, method, INLINE_AFTER_PARSING); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph); SnippetGraphUnderConstruction.set(null); graph.setGuardsStage(GuardsStage.FLOATING_GUARDS); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Thu May 28 17:44:05 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.debug.internal.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.lir.asm.*; @@ -194,9 +193,11 @@ HotSpotRuntimeStub installedCode = new HotSpotRuntimeStub(stub); HotSpotCompiledCode hsCompResult = new HotSpotCompiledRuntimeStub(stub, compResult); - CodeInstallResult result = runtime().getCompilerToVM().installCode(hsCompResult, installedCode, null); - if (result != CodeInstallResult.OK) { - throw new GraalInternalError("Error installing stub %s: %s", Stub.this, result); + HotSpotGraalRuntime runtime = runtime(); + int result = runtime.getCompilerToVM().installCode(hsCompResult, installedCode, null); + HotSpotVMConfig config = runtime.getConfig(); + if (result != config.codeInstallResultOk) { + throw new GraalInternalError("Error installing stub %s: %s", Stub.this, config.getCodeInstallResultDescription(result)); } ((HotSpotCodeCacheProvider) codeCache).logOrDump(installedCode, compResult); code = installedCode; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/KlassPointer.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/KlassPointer.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/KlassPointer.java Thu May 28 17:44:05 2015 +0200 @@ -44,8 +44,8 @@ public static native KlassPointer fromWord(Pointer pointer); @HotSpotOperation(opcode = READ_KLASS_POINTER) - public native KlassPointer readKlassPointer(int secondarySuperCacheOffset, LocationIdentity secondarySuperCacheLocation); + public native KlassPointer readKlassPointer(int offset, LocationIdentity locationIdentity); @Operation(opcode = Opcode.WRITE_POINTER) - public native void writeKlassPointer(int secondarySuperCacheOffset, KlassPointer t, LocationIdentity secondarySuperCacheLocation); + public native void writeKlassPointer(int offset, KlassPointer t, LocationIdentity locationIdentity); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/MetaspacePointer.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/MetaspacePointer.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/MetaspacePointer.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -25,8 +25,8 @@ import static com.oracle.graal.hotspot.word.HotSpotOperation.HotspotOpcode.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.HeapAccess.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1257 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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.java; - -import static com.oracle.graal.api.code.TypeCheckHints.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.bytecode.Bytecodes.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.bytecode.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.options.*; -import com.oracle.graal.phases.*; - -public abstract class AbstractBytecodeParser { - - public static class Options { - // @formatter:off - @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) - public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); - - @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) - public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(false); - - @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert) - public static final StableOptionValue InlineIntrinsicsDuringParsing = new StableOptionValue<>(true); - - @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); - - @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); - - @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); - - @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); - - @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) - public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); - - @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) - public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); - - // @formatter:on - } - - /** - * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the - * bytecode instructions as they are parsed. - */ - public static final int TRACELEVEL_INSTRUCTIONS = 1; - - /** - * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the - * frame state before each bytecode instruction as it is parsed. - */ - public static final int TRACELEVEL_STATE = 2; - - protected HIRFrameStateBuilder frameState; - protected BciBlock currentBlock; - - protected final BytecodeStream stream; - protected final GraphBuilderConfiguration graphBuilderConfig; - protected final ResolvedJavaMethod method; - protected final ProfilingInfo profilingInfo; - protected final OptimisticOptimizations optimisticOpts; - protected final ConstantPool constantPool; - protected final MetaAccessProvider metaAccess; - - protected final ReplacementContext replacementContext; - - /** - * Meters the number of actual bytecodes parsed. - */ - public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed"); - - public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, - ReplacementContext replacementContext) { - this.graphBuilderConfig = graphBuilderConfig; - this.optimisticOpts = optimisticOpts; - this.metaAccess = metaAccess; - this.stream = new BytecodeStream(method.getCode()); - this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null); - this.constantPool = method.getConstantPool(); - this.method = method; - this.replacementContext = replacementContext; - assert metaAccess != null; - } - - public void setCurrentFrameState(HIRFrameStateBuilder frameState) { - this.frameState = frameState; - } - - protected final BytecodeStream getStream() { - return stream; - } - - public int bci() { - return stream.currentBCI(); - } - - public void loadLocal(int index, Kind kind) { - frameState.push(kind, frameState.loadLocal(index)); - } - - public void storeLocal(Kind kind, int index) { - ValueNode value; - if (kind == Kind.Object) { - value = frameState.xpop(); - // astore and astore_ may be used to store a returnAddress (jsr) - assert parsingReplacement() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind(); - } else { - value = frameState.pop(kind); - } - frameState.storeLocal(index, value, kind); - } - - /** - * @param type the unresolved type of the constant - */ - protected abstract void handleUnresolvedLoadConstant(JavaType type); - - /** - * @param type the unresolved type of the type check - * @param object the object value whose type is being checked against {@code type} - */ - protected abstract void handleUnresolvedCheckCast(JavaType type, ValueNode object); - - /** - * @param type the unresolved type of the type check - * @param object the object value whose type is being checked against {@code type} - */ - protected abstract void handleUnresolvedInstanceOf(JavaType type, ValueNode object); - - /** - * @param type the type being instantiated - */ - protected abstract void handleUnresolvedNewInstance(JavaType type); - - /** - * @param type the type of the array being instantiated - * @param length the length of the array - */ - protected abstract void handleUnresolvedNewObjectArray(JavaType type, ValueNode length); - - /** - * @param type the type being instantiated - * @param dims the dimensions for the multi-array - */ - protected abstract void handleUnresolvedNewMultiArray(JavaType type, List dims); - - /** - * @param field the unresolved field - * @param receiver the object containing the field or {@code null} if {@code field} is static - */ - protected abstract void handleUnresolvedLoadField(JavaField field, ValueNode receiver); - - /** - * @param field the unresolved field - * @param value the value being stored to the field - * @param receiver the object containing the field or {@code null} if {@code field} is static - */ - protected abstract void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver); - - /** - * @param type - */ - protected abstract void handleUnresolvedExceptionType(JavaType type); - - // protected abstract void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind); - - // protected abstract DispatchBeginNode handleException(ValueNode exceptionObject, int bci); - - private void genLoadConstant(int cpi, int opcode) { - Object con = lookupConstant(cpi, opcode); - - if (con instanceof JavaType) { - // this is a load of class constant which might be unresolved - JavaType type = (JavaType) con; - if (type instanceof ResolvedJavaType) { - frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass())); - } else { - handleUnresolvedLoadConstant(type); - } - } else if (con instanceof JavaConstant) { - JavaConstant constant = (JavaConstant) con; - frameState.push(constant.getKind().getStackKind(), appendConstant(constant)); - } else { - throw new Error("lookupConstant returned an object of incorrect type"); - } - } - - protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind); - - private void genLoadIndexed(Kind kind) { - ValueNode index = frameState.ipop(); - ValueNode array = emitExplicitExceptions(frameState.apop(), index); - if (!tryLoadIndexedPlugin(kind, index, array)) { - frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); - } - } - - protected abstract void traceWithContext(String format, Object... args); - - protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) { - LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin(); - if (loadIndexedPlugin != null && loadIndexedPlugin.apply((GraphBuilderContext) this, array, index, kind)) { - if (TraceParserPlugins.getValue()) { - traceWithContext("used load indexed plugin"); - } - return true; - } else { - return false; - } - } - - protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); - - private void genStoreIndexed(Kind kind) { - ValueNode value = frameState.pop(kind.getStackKind()); - ValueNode index = frameState.ipop(); - ValueNode array = emitExplicitExceptions(frameState.apop(), index); - genStoreIndexed(array, index, kind, value); - } - - private void stackOp(int opcode) { - switch (opcode) { - case DUP_X1: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP_X2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X1: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - ValueNode w4 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w4); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case SWAP: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - break; - } - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - protected abstract ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - private void genArithmeticOp(Kind result, int opcode) { - ValueNode y = frameState.pop(result); - ValueNode x = frameState.pop(result); - boolean isStrictFP = method.isStrict(); - ValueNode v; - switch (opcode) { - case IADD: - case LADD: - v = genIntegerAdd(result, x, y); - break; - case FADD: - case DADD: - v = genFloatAdd(result, x, y, isStrictFP); - break; - case ISUB: - case LSUB: - v = genIntegerSub(result, x, y); - break; - case FSUB: - case DSUB: - v = genFloatSub(result, x, y, isStrictFP); - break; - case IMUL: - case LMUL: - v = genIntegerMul(result, x, y); - break; - case FMUL: - case DMUL: - v = genFloatMul(result, x, y, isStrictFP); - break; - case FDIV: - case DDIV: - v = genFloatDiv(result, x, y, isStrictFP); - break; - case FREM: - case DREM: - v = genFloatRem(result, x, y, isStrictFP); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(result, append(v)); - } - - protected abstract ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y); - - private void genIntegerDivOp(Kind result, int opcode) { - ValueNode y = frameState.pop(result); - ValueNode x = frameState.pop(result); - ValueNode v; - switch (opcode) { - case IDIV: - case LDIV: - v = genIntegerDiv(result, x, y); - break; - case IREM: - case LREM: - v = genIntegerRem(result, x, y); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(result, append(v)); - } - - protected abstract ValueNode genNegateOp(ValueNode x); - - private void genNegateOp(Kind kind) { - frameState.push(kind, append(genNegateOp(frameState.pop(kind)))); - } - - protected abstract ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y); - - private void genShiftOp(Kind kind, int opcode) { - ValueNode s = frameState.ipop(); - ValueNode x = frameState.pop(kind); - ValueNode v; - switch (opcode) { - case ISHL: - case LSHL: - v = genLeftShift(kind, x, s); - break; - case ISHR: - case LSHR: - v = genRightShift(kind, x, s); - break; - case IUSHR: - case LUSHR: - v = genUnsignedRightShift(kind, x, s); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(kind, append(v)); - } - - protected abstract ValueNode genAnd(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genOr(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genXor(Kind kind, ValueNode x, ValueNode y); - - private void genLogicOp(Kind kind, int opcode) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - ValueNode v; - switch (opcode) { - case IAND: - case LAND: - v = genAnd(kind, x, y); - break; - case IOR: - case LOR: - v = genOr(kind, x, y); - break; - case IXOR: - case LXOR: - v = genXor(kind, x, y); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(kind, append(v)); - } - - protected abstract ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess); - - private void genCompareOp(Kind kind, boolean isUnorderedLess) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess))); - } - - protected abstract ValueNode genFloatConvert(FloatConvert op, ValueNode input); - - private void genFloatConvert(FloatConvert op, Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - frameState.push(to.getStackKind(), append(genFloatConvert(op, input))); - } - - protected abstract ValueNode genNarrow(ValueNode input, int bitCount); - - protected abstract ValueNode genSignExtend(ValueNode input, int bitCount); - - protected abstract ValueNode genZeroExtend(ValueNode input, int bitCount); - - private void genSignExtend(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - if (from != from.getStackKind()) { - input = append(genNarrow(input, from.getBitCount())); - } - frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount()))); - } - - private void genZeroExtend(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - if (from != from.getStackKind()) { - input = append(genNarrow(input, from.getBitCount())); - } - frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount()))); - } - - private void genNarrow(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount()))); - } - - private void genIncrement() { - int index = getStream().readLocalIndex(); - int delta = getStream().readIncrement(); - ValueNode x = frameState.loadLocal(index); - ValueNode y = appendConstant(JavaConstant.forInt(delta)); - frameState.storeLocal(index, append(genIntegerAdd(Kind.Int, x, y))); - } - - protected abstract void genGoto(); - - protected abstract ValueNode genObjectEquals(ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerEquals(ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerLessThan(ValueNode x, ValueNode y); - - protected abstract ValueNode genUnique(ValueNode x); - - protected abstract void genIf(ValueNode x, Condition cond, ValueNode y); - - private void genIfZero(Condition cond) { - ValueNode y = appendConstant(JavaConstant.INT_0); - ValueNode x = frameState.ipop(); - genIf(x, cond, y); - } - - private void genIfNull(Condition cond) { - ValueNode y = appendConstant(JavaConstant.NULL_POINTER); - ValueNode x = frameState.apop(); - genIf(x, cond, y); - } - - private void genIfSame(Kind kind, Condition cond) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - genIf(x, cond, y); - } - - protected abstract void genThrow(); - - protected JavaType lookupType(int cpi, int bytecode) { - maybeEagerlyResolve(cpi, bytecode); - JavaType result = constantPool.lookupType(cpi, bytecode); - assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; - return result; - } - - private JavaMethod lookupMethod(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - JavaMethod result = constantPool.lookupMethod(cpi, opcode); - /* - * In general, one cannot assume that the declaring class being initialized is useful, since - * the actual concrete receiver may be a different class (except for static calls). Also, - * interfaces are initialized only under special circumstances, so that this assertion would - * often fail for interface calls. - */ - assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; - return result; - } - - private JavaField lookupField(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - JavaField result = constantPool.lookupField(cpi, opcode); - assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; - return result; - } - - private Object lookupConstant(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - Object result = constantPool.lookupConstant(cpi); - assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; - return result; - } - - private void maybeEagerlyResolve(int cpi, int bytecode) { - if (graphBuilderConfig.eagerResolving() || replacementContext instanceof IntrinsicContext) { - constantPool.loadReferencedType(cpi, bytecode); - } - } - - private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { - if (parsingReplacement() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { - return null; - } else { - return profilingInfo.getTypeProfile(bci()); - } - } - - protected abstract ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck); - - private void genCheckCast() { - int cpi = getStream().readCPI(); - JavaType type = lookupType(cpi, CHECKCAST); - ValueNode object = frameState.apop(); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !typeCheckPlugin.checkCast((GraphBuilderContext) this, object, resolvedType, profile)) { - ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); - frameState.apush(checkCastNode); - } - } else { - handleUnresolvedCheckCast(type, object); - } - } - - protected abstract ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck); - - protected abstract ValueNode genConditional(ValueNode x); - - private void genInstanceOf() { - int cpi = getStream().readCPI(); - JavaType type = lookupType(cpi, INSTANCEOF); - ValueNode object = frameState.apop(); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf((GraphBuilderContext) this, object, resolvedType, profile)) { - ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile); - frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); - } - } else { - handleUnresolvedInstanceOf(type, object); - } - } - - protected abstract ValueNode createNewInstance(ResolvedJavaType type, boolean fillContents); - - void genNewInstance(int cpi) { - JavaType type = lookupType(cpi, NEW); - if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { - ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); - if (skippedExceptionTypes != null) { - for (ResolvedJavaType exceptionType : skippedExceptionTypes) { - if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) { - append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); - return; - } - } - } - frameState.apush(append(createNewInstance((ResolvedJavaType) type, true))); - } else { - handleUnresolvedNewInstance(type); - } - } - - /** - * Gets the kind of array elements for the array type code that appears in a - * {@link Bytecodes#NEWARRAY} bytecode. - * - * @param code the array type code - * @return the kind from the array type code - */ - public static Class arrayTypeCodeToClass(int code) { - // Checkstyle: stop - switch (code) { - case 4: - return boolean.class; - case 5: - return char.class; - case 6: - return float.class; - case 7: - return double.class; - case 8: - return byte.class; - case 9: - return short.class; - case 10: - return int.class; - case 11: - return long.class; - default: - throw new IllegalArgumentException("unknown array type code: " + code); - } - // Checkstyle: resume - } - - private void genNewPrimitiveArray(int typeCode) { - Class clazz = arrayTypeCodeToClass(typeCode); - ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz); - frameState.apush(append(createNewArray(elementType, frameState.ipop(), true))); - } - - private void genNewObjectArray(int cpi) { - JavaType type = lookupType(cpi, ANEWARRAY); - ValueNode length = frameState.ipop(); - if (type instanceof ResolvedJavaType) { - frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true))); - } else { - handleUnresolvedNewObjectArray(type, length); - } - - } - - protected abstract ValueNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents); - - private void genNewMultiArray(int cpi) { - JavaType type = lookupType(cpi, MULTIANEWARRAY); - int rank = getStream().readUByte(bci() + 3); - List dims = new ArrayList<>(Collections.nCopies(rank, null)); - for (int i = rank - 1; i >= 0; i--) { - dims.set(i, frameState.ipop()); - } - if (type instanceof ResolvedJavaType) { - frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims))); - } else { - handleUnresolvedNewMultiArray(type, dims); - } - } - - protected abstract ValueNode createNewMultiArray(ResolvedJavaType type, List dims); - - protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field); - - private void genGetField(JavaField field) { - Kind kind = field.getKind(); - ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); - if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { - appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); - } - } else { - handleUnresolvedLoadField(field, receiver); - } - } - - /** - * Emits control flow to null check a receiver if it's stamp does not indicate it is - * {@linkplain StampTool#isPointerNonNull always non-null}. - * - * @return the receiver with a stamp indicating non-nullness - */ - protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver); - - /** - * Emits control flow to check an array index is within bounds of an array's length. - * - * @param index the index to check - * @param length the length of the array being indexed - */ - protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length); - - private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); - - protected abstract ValueNode genArrayLength(ValueNode x); - - /** - * @param receiver the receiver of an object based operation - * @param index the index of an array based operation that is to be tested for out of bounds. - * This is null for a non-array operation. - * @return the receiver value possibly modified to have a tighter stamp - */ - protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { - assert receiver != null; - if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null || - (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { - return receiver; - } - - ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); - if (index != null) { - ValueNode length = append(genArrayLength(nonNullReceiver)); - emitExplicitBoundsCheck(index, length); - } - EXPLICIT_EXCEPTIONS.increment(); - return nonNullReceiver; - } - - protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); - - private void genPutField(JavaField field) { - ValueNode value = frameState.pop(field.getKind().getStackKind()); - ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); - if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - genStoreField(receiver, (ResolvedJavaField) field, value); - } else { - handleUnresolvedStoreField(field, value, receiver); - } - } - - private void genGetStatic(JavaField field) { - Kind kind = field.getKind(); - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) { - appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field)); - } - } else { - handleUnresolvedLoadField(field, null); - } - } - - public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) { - return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field); - } - - private void genPutStatic(JavaField field) { - ValueNode value = frameState.pop(field.getKind().getStackKind()); - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - genStoreField(null, (ResolvedJavaField) field, value); - } else { - handleUnresolvedStoreField(field, value, null); - } - } - - protected void appendOptimizedLoadField(Kind kind, ValueNode load) { - // append the load to the instruction - ValueNode optimized = append(load); - frameState.push(kind.getStackKind(), optimized); - } - - protected abstract void genInvokeStatic(JavaMethod target); - - protected abstract void genInvokeInterface(JavaMethod target); - - protected abstract void genInvokeDynamic(JavaMethod target); - - protected abstract void genInvokeVirtual(JavaMethod target); - - protected abstract void genInvokeSpecial(JavaMethod target); - - protected abstract void genReturn(ValueNode x, Kind kind); - - protected abstract void genMonitorEnter(ValueNode x, int bci); - - protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci); - - protected abstract void genJsr(int dest); - - protected abstract void genRet(int localIndex); - - private double[] switchProbability(int numberOfCases, int bci) { - double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); - if (prob != null) { - assert prob.length == numberOfCases; - } else { - Debug.log("Missing probability (switch) in %s at bci %d", method, bci); - prob = new double[numberOfCases]; - for (int i = 0; i < numberOfCases; i++) { - prob[i] = 1.0d / numberOfCases; - } - } - assert allPositive(prob); - return prob; - } - - private static boolean allPositive(double[] a) { - for (double d : a) { - if (d < 0) { - return false; - } - } - return true; - } - - /** - * Helper function that sums up the probabilities of all keys that lead to a specific successor. - * - * @return an array of size successorCount with the accumulated probability for each successor. - */ - public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { - double[] probability = new double[successorCount]; - for (int i = 0; i < keySuccessors.length; i++) { - probability[keySuccessors[i]] += keyProbabilities[i]; - } - return probability; - } - - private void genSwitch(BytecodeSwitch bs) { - int bci = bci(); - ValueNode value = frameState.ipop(); - - int nofCases = bs.numberOfCases(); - double[] keyProbabilities = switchProbability(nofCases + 1, bci); - - Map bciToBlockSuccessorIndex = new HashMap<>(); - for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { - assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); - if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { - bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); - } - } - - ArrayList actualSuccessors = new ArrayList<>(); - int[] keys = new int[nofCases]; - int[] keySuccessors = new int[nofCases + 1]; - int deoptSuccessorIndex = -1; - int nextSuccessorIndex = 0; - boolean constantValue = value.isConstant(); - for (int i = 0; i < nofCases + 1; i++) { - if (i < nofCases) { - keys[i] = bs.keyAt(i); - } - - if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { - if (deoptSuccessorIndex < 0) { - deoptSuccessorIndex = nextSuccessorIndex++; - actualSuccessors.add(null); - } - keySuccessors[i] = deoptSuccessorIndex; - } else { - int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); - SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); - if (info.actualIndex < 0) { - info.actualIndex = nextSuccessorIndex++; - actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); - } - keySuccessors[i] = info.actualIndex; - } - } - - genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); - - } - - protected abstract void genIntegerSwitch(ValueNode value, ArrayList actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors); - - private static class SuccessorInfo { - - int blockIndex; - int actualIndex; - - public SuccessorInfo(int blockSuccessorIndex) { - this.blockIndex = blockSuccessorIndex; - actualIndex = -1; - } - } - - protected abstract ValueNode appendConstant(JavaConstant constant); - - protected abstract T append(T v); - - protected boolean isNeverExecutedCode(double probability) { - return probability == 0 && optimisticOpts.removeNeverExecutedCode(); - } - - protected double branchProbability() { - if (profilingInfo == null) { - return 0.5; - } - assert assertAtIfBytecode(); - double probability = profilingInfo.getBranchTakenProbability(bci()); - if (probability < 0) { - assert probability == -1 : "invalid probability"; - Debug.log("missing probability in %s at bci %d", method, bci()); - probability = 0.5; - } - - if (!optimisticOpts.removeNeverExecutedCode()) { - if (probability == 0) { - probability = 0.0000001; - } else if (probability == 1) { - probability = 0.999999; - } - } - return probability; - } - - private boolean assertAtIfBytecode() { - int bytecode = stream.currentBC(); - switch (bytecode) { - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - case IFNULL: - case IFNONNULL: - return true; - } - assert false : String.format("%x is not an if bytecode", bytecode); - return true; - } - - protected abstract void iterateBytecodesForBlock(BciBlock block); - - public final void processBytecode(int bci, int opcode) { - int cpi; - - // Checkstyle: stop - // @formatter:off - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; - case ICONST_M1 : // fall through - case ICONST_0 : // fall through - case ICONST_1 : // fall through - case ICONST_2 : // fall through - case ICONST_3 : // fall through - case ICONST_4 : // fall through - case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; - case LCONST_0 : // fall through - case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; - case FCONST_0 : // fall through - case FCONST_1 : // fall through - case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; - case DCONST_0 : // fall through - case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; - case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; - case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; - case IALOAD : genLoadIndexed(Kind.Int ); break; - case LALOAD : genLoadIndexed(Kind.Long ); break; - case FALOAD : genLoadIndexed(Kind.Float ); break; - case DALOAD : genLoadIndexed(Kind.Double); break; - case AALOAD : genLoadIndexed(Kind.Object); break; - case BALOAD : genLoadIndexed(Kind.Byte ); break; - case CALOAD : genLoadIndexed(Kind.Char ); break; - case SALOAD : genLoadIndexed(Kind.Short ); break; - case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(Kind.Int ); break; - case LASTORE : genStoreIndexed(Kind.Long ); break; - case FASTORE : genStoreIndexed(Kind.Float ); break; - case DASTORE : genStoreIndexed(Kind.Double); break; - case AASTORE : genStoreIndexed(Kind.Object); break; - case BASTORE : genStoreIndexed(Kind.Byte ); break; - case CASTORE : genStoreIndexed(Kind.Char ); break; - case SASTORE : genStoreIndexed(Kind.Short ); break; - case POP : frameState.xpop(); break; - case POP2 : frameState.xpop(); frameState.xpop(); break; - case DUP : frameState.xpush(frameState.xpeek()); break; - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(Kind.Int, opcode); break; - case IDIV : // fall through - case IREM : genIntegerDivOp(Kind.Int, opcode); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(Kind.Long, opcode); break; - case LDIV : // fall through - case LREM : genIntegerDivOp(Kind.Long, opcode); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(Kind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(Kind.Double, opcode); break; - case INEG : genNegateOp(Kind.Int); break; - case LNEG : genNegateOp(Kind.Long); break; - case FNEG : genNegateOp(Kind.Float); break; - case DNEG : genNegateOp(Kind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(Kind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(Kind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(Kind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(Kind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; - case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; - case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; - case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; - case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; - case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; - case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; - case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; - case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; - case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; - case L2I : genNarrow(Kind.Long, Kind.Int); break; - case I2L : genSignExtend(Kind.Int, Kind.Long); break; - case I2B : genSignExtend(Kind.Byte, Kind.Int); break; - case I2S : genSignExtend(Kind.Short, Kind.Int); break; - case I2C : genZeroExtend(Kind.Char, Kind.Int); break; - case LCMP : genCompareOp(Kind.Long, false); break; - case FCMPL : genCompareOp(Kind.Float, true); break; - case FCMPG : genCompareOp(Kind.Float, false); break; - case DCMPL : genCompareOp(Kind.Double, true); break; - case DCMPG : genCompareOp(Kind.Double, false); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; - case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; - case GOTO : genGoto(); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; - case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; - case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; - case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; - case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; - case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; - case ARETURN : genReturn(frameState.apop(), Kind.Object); break; - case RETURN : genReturn(null, Kind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(); break; - case JSR_W : genJsr(stream.readBranchDest()); break; - case BREAKPOINT: - throw new BailoutException("concurrent setting of breakpoint"); - default: - throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); - } - // @formatter:on - // Checkstyle: resume - } - - private void genArrayLength() { - frameState.ipush(append(genArrayLength(frameState.apop()))); - } - - public ResolvedJavaMethod getMethod() { - return method; - } - - public HIRFrameStateBuilder getFrameState() { - return frameState; - } - - protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { - if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { - traceInstructionHelper(bci, opcode, blockStart); - } - return true; - } - - private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { - StringBuilder sb = new StringBuilder(40); - sb.append(blockStart ? '+' : '|'); - if (bci < 10) { - sb.append(" "); - } else if (bci < 100) { - sb.append(' '); - } - sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); - for (int i = bci + 1; i < stream.nextBCI(); ++i) { - sb.append(' ').append(stream.readUByte(i)); - } - if (!currentBlock.getJsrScope().isEmpty()) { - sb.append(' ').append(currentBlock.getJsrScope()); - } - Debug.log("%s", sb); - } - - public boolean parsingReplacement() { - return replacementContext != null; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,451 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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.java; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; - -public abstract class AbstractFrameStateBuilder> { - - protected final ResolvedJavaMethod method; - protected int stackSize; - protected final T[] locals; - protected final T[] stack; - protected T[] lockedObjects; - - protected final BytecodeParser parser; - - /** - * @see BytecodeFrame#rethrowException - */ - protected boolean rethrowException; - - public AbstractFrameStateBuilder(ResolvedJavaMethod method, BytecodeParser parser) { - this.method = method; - this.parser = parser; - this.locals = allocateArray(method.getMaxLocals()); - this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); - this.lockedObjects = allocateArray(0); - } - - protected AbstractFrameStateBuilder(S other) { - this.method = other.method; - this.parser = other.parser; - this.stackSize = other.stackSize; - this.locals = other.locals.clone(); - this.stack = other.stack.clone(); - this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); - this.rethrowException = other.rethrowException; - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - } - - public abstract S copy(); - - protected abstract T[] allocateArray(int length); - - public abstract boolean isCompatibleWith(S other); - - public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { - /* - * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to - * remove it for normal compilations, but not for OSR compilations - otherwise dead object - * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with - * Kind.Illegal, because the conflicting branch might not have been parsed. - */ - if (liveness == null) { - return; - } - if (liveIn) { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveIn(block, i)) { - locals[i] = null; - } - } - } else { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveOut(block, i)) { - locals[i] = null; - } - } - } - } - - /** - * @see BytecodeFrame#rethrowException - */ - public boolean rethrowException() { - return rethrowException; - } - - /** - * @see BytecodeFrame#rethrowException - */ - public void setRethrowException(boolean b) { - rethrowException = b; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * @return the current lock depth - */ - public int lockDepth() { - return lockedObjects.length; - } - - /** - * Gets the value in the local variables at the specified index, without any sanity checking. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public T localAt(int i) { - return locals[i]; - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public T stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the lock at the specified index, without any sanity checking. - * - * @param i the index into the lock - * @return the instruction that produced the value for the specified lock - */ - public T lockAt(int i) { - return lockedObjects[i]; - } - - public void storeLock(int i, T lock) { - lockedObjects[i] = lock; - } - - /** - * Loads the local variable at the specified index, checking that the returned value is non-null - * and that two-stack values are properly handled. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public T loadLocal(int i) { - T x = locals[i]; - assert x != null : i; - assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); - assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); - return x; - } - - public void storeLocal(int i, T x) { - storeLocal(i, x, x == null ? null : x.getKind()); - } - - /** - * Stores a given local variable at the specified index. If the value occupies two slots, then - * the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, T x, Kind kind) { - assert x == null || parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; - locals[i] = x; - if (x != null) { - if (kind.needsTwoSlots() && !parser.parsingReplacement()) { - // if this is a double word, then kill i+1 - locals[i + 1] = null; - } - if (i > 0 && !parser.parsingReplacement()) { - T p = locals[i - 1]; - if (p != null && p.getKind().needsTwoSlots()) { - // if there was a double word at i - 1, then kill it - locals[i - 1] = null; - } - } - } - } - - public void storeStack(int i, T x) { - assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; - stack[i] = x; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(Kind kind, T x) { - assert kind != Kind.Void && kind != Kind.Illegal : kind + ":" + x; - xpush(assertKind(kind, x)); - if (kind.needsTwoSlots()) { - xpush(null); - } - } - - /** - * Pushes a value onto the stack without checking the type. - * - * @param x the instruction to push onto the stack - */ - public void xpush(T x) { - assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); - stack[stackSize++] = x; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * - * @param x the instruction to push onto the stack - */ - public void ipush(T x) { - xpush(assertInt(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * - * @param x the instruction to push onto the stack - */ - public void fpush(T x) { - xpush(assertFloat(x)); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * - * @param x the instruction to push onto the stack - */ - public void apush(T x) { - xpush(assertObject(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(T x) { - xpush(assertLong(x)); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * - * @param x the instruction to push onto the stack - */ - public void dpush(T x) { - xpush(assertDouble(x)); - xpush(null); - } - - public void pushReturn(Kind kind, T x) { - if (kind != Kind.Void) { - push(kind.getStackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public T pop(Kind kind) { - assert kind != Kind.Void; - if (kind.needsTwoSlots()) { - xpop(); - } - return assertKind(kind, xpop()); - } - - /** - * Pops a value off of the stack without checking the type. - * - * @return x the instruction popped off the stack - */ - public T xpop() { - T result = stack[--stackSize]; - return result; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * - * @return x the instruction popped off the stack - */ - public T ipop() { - return assertInt(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * - * @return x the instruction popped off the stack - */ - public T fpop() { - return assertFloat(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * - * @return x the instruction popped off the stack - */ - public T apop() { - return assertObject(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * - * @return x the instruction popped off the stack - */ - public T lpop() { - assertHigh(xpop()); - return assertLong(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * - * @return x the instruction popped off the stack - */ - public T dpop() { - assertHigh(xpop()); - return assertDouble(xpop()); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of - * instructions. - * - * @return an array containing the arguments off of the stack - */ - public T[] popArguments(int argSize) { - T[] result = allocateArray(argSize); - int newStackSize = stackSize; - for (int i = argSize - 1; i >= 0; i--) { - newStackSize--; - if (stack[newStackSize] == null) { - /* Two-slot value. */ - newStackSize--; - assert stack[newStackSize].getKind().needsTwoSlots(); - } else { - assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1); - } - result[i] = stack[newStackSize]; - } - stackSize = newStackSize; - return result; - } - - /** - * Peeks an element from the operand stack. - * - * @param argumentNumber The number of the argument, relative from the top of the stack (0 = - * top). Long and double arguments only count as one argument, i.e., null-slots are - * ignored. - * @return The peeked argument. - */ - public T peek(int argumentNumber) { - int idx = stackSize() - 1; - for (int i = 0; i < argumentNumber; i++) { - if (stackAt(idx) == null) { - idx--; - assert stackAt(idx).getKind().needsTwoSlots(); - } - idx--; - } - return stackAt(idx); - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackSize = 0; - } - - private T assertKind(Kind kind, T x) { - assert x != null && (parser.parsingReplacement() || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind()); - return x; - } - - private T assertLong(T x) { - assert x != null && (x.getKind() == Kind.Long); - return x; - } - - private T assertInt(T x) { - assert x != null && (x.getKind() == Kind.Int); - return x; - } - - private T assertFloat(T x) { - assert x != null && (x.getKind() == Kind.Float); - return x; - } - - private T assertObject(T x) { - assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object)); - return x; - } - - private T assertDouble(T x) { - assert x != null && (x.getKind() == Kind.Double); - return x; - } - - private void assertHigh(T x) { - assert x == null; - } - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,1036 @@ +/* + * Copyright (c) 2012, 2015, 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.java; + +import static com.oracle.graal.graph.iterators.NodePredicates.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graphbuilderconf.IntrinsicContext.SideEffectsState; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.util.*; + +public final class FrameStateBuilder implements SideEffectsState { + + static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + + protected final BytecodeParser parser; + protected final ResolvedJavaMethod method; + protected int stackSize; + protected final ValueNode[] locals; + protected final ValueNode[] stack; + protected ValueNode[] lockedObjects; + + /** + * @see BytecodeFrame#rethrowException + */ + protected boolean rethrowException; + + private MonitorIdNode[] monitorIds; + private final StructuredGraph graph; + private FrameState outerFrameState; + + /** + * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more + * than one when the current block contains no side-effects but merging predecessor blocks do. + */ + protected List sideEffects; + + /** + * Creates a new frame state builder for the given method and the given target graph. + * + * @param method the method whose frame is simulated + * @param graph the target graph of Graal nodes created by the builder + */ + public FrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) { + this.parser = parser; + this.method = method; + this.locals = allocateArray(method.getMaxLocals()); + this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); + this.lockedObjects = allocateArray(0); + + assert graph != null; + + this.monitorIds = EMPTY_MONITOR_ARRAY; + this.graph = graph; + } + + public void initializeFromArgumentsArray(ValueNode[] arguments) { + + int javaIndex = 0; + int index = 0; + if (!method.isStatic()) { + // set the receiver + locals[javaIndex] = arguments[index]; + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + for (int i = 0; i < max; i++) { + Kind kind = sig.getParameterKind(i); + locals[javaIndex] = arguments[index]; + javaIndex += kind.getSlotCount(); + index++; + } + } + + public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { + + int javaIndex = 0; + int index = 0; + if (!method.isStatic()) { + // add the receiver + FloatingNode receiver = null; + Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass()); + if (parameterPlugin != null) { + receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp); + } + if (receiver == null) { + receiver = new ParameterNode(javaIndex, receiverStamp); + } + locals[javaIndex] = graph.unique(receiver); + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + if (eagerResolve) { + type = type.resolve(accessingClass); + } + Kind kind = type.getKind(); + Stamp stamp; + if (kind == Kind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.declared((ResolvedJavaType) type); + } else { + stamp = StampFactory.forKind(kind); + } + FloatingNode param = null; + if (parameterPlugin != null) { + param = parameterPlugin.interceptParameter(parser, index, stamp); + } + if (param == null) { + param = new ParameterNode(index, stamp); + } + locals[javaIndex] = graph.unique(param); + javaIndex += kind.getSlotCount(); + index++; + } + } + + private FrameStateBuilder(FrameStateBuilder other) { + this.parser = other.parser; + this.method = other.method; + this.stackSize = other.stackSize; + this.locals = other.locals.clone(); + this.stack = other.stack.clone(); + this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); + this.rethrowException = other.rethrowException; + + assert locals.length == method.getMaxLocals(); + assert stack.length == Math.max(1, method.getMaxStackSize()); + + assert other.graph != null; + graph = other.graph; + monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); + + assert locals.length == method.getMaxLocals(); + assert stack.length == Math.max(1, method.getMaxStackSize()); + assert lockedObjects.length == monitorIds.length; + } + + private static ValueNode[] allocateArray(int length) { + return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[locals: ["); + for (int i = 0; i < locals.length; i++) { + sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); + } + sb.append("] stack: ["); + for (int i = 0; i < stackSize; i++) { + sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); + } + sb.append("] locks: ["); + for (int i = 0; i < lockedObjects.length; i++) { + sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); + } + sb.append("]"); + if (rethrowException) { + sb.append(" rethrowException"); + } + sb.append("]"); + return sb.toString(); + } + + public FrameState create(int bci, StateSplit forStateSplit) { + if (parser.parsingIntrinsic()) { + return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit); + } + + // Skip intrinsic frames + return create(bci, parser.getNonIntrinsicAncestor(), false, (ValueNode[]) null); + } + + /** + * @param pushedValues if non-null, values to {@link #push(Kind, ValueNode)} to the stack before + * creating the {@link FrameState} + */ + public FrameState create(int bci, BytecodeParser parent, boolean duringCall, ValueNode... pushedValues) { + if (outerFrameState == null && parent != null) { + outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), null); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); + return newFrameState; + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw GraalInternalError.shouldNotReachHere(); + } + + if (pushedValues != null) { + int stackSizeToRestore = stackSize; + for (ValueNode arg : pushedValues) { + push(arg.getKind(), arg); + } + FrameState res = graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + stackSize = stackSizeToRestore; + return res; + } else { + return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + } + } + + public BytecodePosition createBytecodePosition(int bci) { + BytecodeParser parent = parser.getParent(); + if (HideSubstitutionStates.getValue()) { + if (parser.parsingIntrinsic()) { + // Attribute to the method being replaced + return new BytecodePosition(parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1); + } + // Skip intrinsic frames + parent = parser.getNonIntrinsicAncestor(); + } + return create(null, bci, parent); + } + + private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) { + BytecodePosition outer = o; + if (outer == null && parent != null) { + outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci()); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + return FrameState.toBytecodePosition(outerFrameState); + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw GraalInternalError.shouldNotReachHere(); + } + return new BytecodePosition(outer, method, bci); + } + + public FrameStateBuilder copy() { + return new FrameStateBuilder(this); + } + + public boolean isCompatibleWith(FrameStateBuilder other) { + assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; + + if (stackSize() != other.stackSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + ValueNode x = stackAt(i); + ValueNode y = other.stackAt(i); + if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) { + return false; + } + } + if (lockedObjects.length != other.lockedObjects.length) { + return false; + } + for (int i = 0; i < lockedObjects.length; i++) { + if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { + throw new BailoutException("unbalanced monitors"); + } + } + return true; + } + + public void merge(AbstractMergeNode block, FrameStateBuilder other) { + assert isCompatibleWith(other); + + for (int i = 0; i < localsSize(); i++) { + ValueNode curLocal = localAt(i); + ValueNode mergedLocal = merge(curLocal, other.localAt(i), block); + if (curLocal != mergedLocal) { + storeLocal(i, mergedLocal); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode curStack = stackAt(i); + ValueNode mergedStack = merge(curStack, other.stackAt(i), block); + if (curStack != mergedStack) { + storeStack(i, mergedStack); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); + assert monitorIds[i] == other.monitorIds[i]; + } + + if (sideEffects == null) { + sideEffects = other.sideEffects; + } else { + if (other.sideEffects != null) { + sideEffects.addAll(other.sideEffects); + } + } + } + + private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + if (currentValue == null || currentValue.isDeleted()) { + return null; + } else if (block.isPhiAtMerge(currentValue)) { + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + propagateDelete((ValuePhiNode) currentValue); + return null; + } + ((PhiNode) currentValue).addInput(otherValue); + return currentValue; + } else if (currentValue != otherValue) { + assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + return null; + } + return createValuePhi(currentValue, otherValue, block); + } else { + return currentValue; + } + } + + private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block)); + for (int i = 0; i < block.phiPredecessorCount(); i++) { + phi.addInput(currentValue); + } + phi.addInput(otherValue); + assert phi.valueCount() == block.phiPredecessorCount() + 1; + return phi; + } + + private void propagateDelete(FloatingNode node) { + assert node instanceof ValuePhiNode || node instanceof ProxyNode; + if (node.isDeleted()) { + return; + } + // Collect all phi functions that use this phi so that we can delete them recursively (after + // we delete ourselves to avoid circles). + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot(); + + // Remove the phi function from all FrameStates where it is used and then delete it. + assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + node.replaceAtUsages(null); + node.safeDelete(); + + for (FloatingNode phiUsage : propagateUsages) { + propagateDelete(phiUsage); + } + } + + public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis) { + for (int i = 0; i < localsSize(); i++) { + boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i); + if (changedInLoop || forcePhis) { + storeLocal(i, createLoopPhi(loopBegin, localAt(i), !changedInLoop)); + } + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, createLoopPhi(loopBegin, stackAt(i), false)); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false); + } + } + + public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + } + + public void insertProxies(AbstractBeginNode begin) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, begin, graph); + } + } + } + + private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) { + if (value == null) { + return null; + } + assert !block.isPhiAtMerge(value) : "phi function for this block already created"; + + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block)); + phi.addInput(value); + return phi; + } + + /** + * Adds a locked monitor to this frame state. + * + * @param object the object whose monitor will be locked. + */ + public void pushLock(ValueNode object, MonitorIdNode monitorId) { + assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object; + lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); + monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); + lockedObjects[lockedObjects.length - 1] = object; + monitorIds[monitorIds.length - 1] = monitorId; + assert lockedObjects.length == monitorIds.length; + } + + /** + * Removes a locked monitor from this frame state. + * + * @return the object whose monitor was removed from the locks list. + */ + public ValueNode popLock() { + try { + return lockedObjects[lockedObjects.length - 1]; + } finally { + lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); + monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); + assert lockedObjects.length == monitorIds.length; + } + } + + public MonitorIdNode peekMonitorId() { + return monitorIds[monitorIds.length - 1]; + } + + /** + * @return the current lock depth + */ + public int lockDepth() { + assert lockedObjects.length == monitorIds.length; + return lockedObjects.length; + } + + public boolean contains(ValueNode value) { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) == value) { + return true; + } + } + for (int i = 0; i < stackSize(); i++) { + if (stackAt(i) == value) { + return true; + } + } + assert lockedObjects.length == monitorIds.length; + for (int i = 0; i < lockedObjects.length; i++) { + if (lockedObjects[i] == value || monitorIds[i] == value) { + return true; + } + } + return false; + } + + public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { + /* + * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to + * remove it for normal compilations, but not for OSR compilations - otherwise dead object + * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with + * Kind.Illegal, because the conflicting branch might not have been parsed. + */ + if (!parser.graphBuilderConfig.clearNonLiveLocals()) { + return; + } + if (liveIn) { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveIn(block, i)) { + locals[i] = null; + } + } + } else { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveOut(block, i)) { + locals[i] = null; + } + } + } + } + + /** + * @see BytecodeFrame#rethrowException + */ + public boolean rethrowException() { + return rethrowException; + } + + /** + * @see BytecodeFrame#rethrowException + */ + public void setRethrowException(boolean b) { + rethrowException = b; + } + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public int localsSize() { + return locals.length; + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + /** + * Gets the value in the local variables at the specified index, without any sanity checking. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + public ValueNode localAt(int i) { + return locals[i]; + } + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + public ValueNode stackAt(int i) { + return stack[i]; + } + + /** + * Gets the value in the lock at the specified index, without any sanity checking. + * + * @param i the index into the lock + * @return the instruction that produced the value for the specified lock + */ + public ValueNode lockAt(int i) { + return lockedObjects[i]; + } + + public void storeLock(int i, ValueNode lock) { + lockedObjects[i] = lock; + } + + /** + * Loads the local variable at the specified index, checking that the returned value is non-null + * and that two-stack values are properly handled. + * + * @param i the index of the local variable to load + * @return the instruction that produced the specified local + */ + public ValueNode loadLocal(int i) { + ValueNode x = locals[i]; + assert assertLoadLocal(i, x); + return x; + } + + private boolean assertLoadLocal(int i, ValueNode x) { + assert x != null : i; + assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); + assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); + return true; + } + + public void storeLocal(int i, ValueNode x) { + storeLocal(i, x, x == null ? null : x.getKind()); + } + + /** + * Stores a given local variable at the specified index. If the value occupies two slots, then + * the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, ValueNode x, Kind kind) { + assert assertStoreLocal(x); + locals[i] = x; + if (x != null) { + if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) { + // if this is a double word, then kill i+1 + locals[i + 1] = null; + } + if (i > 0 && !parser.parsingIntrinsic()) { + ValueNode p = locals[i - 1]; + if (p != null && p.getKind().needsTwoSlots()) { + // if there was a double word at i - 1, then kill it + locals[i - 1] = null; + } + } + } + } + + private boolean assertStoreLocal(ValueNode x) { + assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; + return true; + } + + public void storeStack(int i, ValueNode x) { + assert assertStoreStack(i, x); + stack[i] = x; + } + + private boolean assertStoreStack(int i, ValueNode x) { + assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; + return true; + } + + /** + * Pushes an instruction onto the stack with the expected type. + * + * @param kind the type expected for this instruction + * @param x the instruction to push onto the stack + */ + public void push(Kind kind, ValueNode x) { + assert assertPush(kind, x); + xpush(x); + if (kind.needsTwoSlots()) { + xpush(null); + } + } + + private boolean assertPush(Kind kind, ValueNode x) { + assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); + assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); + return true; + } + + /** + * Pushes a value onto the stack without checking the type. + * + * @param x the instruction to push onto the stack + */ + public void xpush(ValueNode x) { + assert assertXpush(x); + stack[stackSize++] = x; + } + + private boolean assertXpush(ValueNode x) { + assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); + return true; + } + + /** + * Pushes a value onto the stack and checks that it is an int. + * + * @param x the instruction to push onto the stack + */ + public void ipush(ValueNode x) { + assert assertInt(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is a float. + * + * @param x the instruction to push onto the stack + */ + public void fpush(ValueNode x) { + assert assertFloat(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is an object. + * + * @param x the instruction to push onto the stack + */ + public void apush(ValueNode x) { + assert assertObject(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is a long. + * + * @param x the instruction to push onto the stack + */ + public void lpush(ValueNode x) { + assert assertLong(x); + xpush(x); + xpush(null); + } + + /** + * Pushes a value onto the stack and checks that it is a double. + * + * @param x the instruction to push onto the stack + */ + public void dpush(ValueNode x) { + assert assertDouble(x); + xpush(x); + xpush(null); + } + + public void pushReturn(Kind kind, ValueNode x) { + if (kind != Kind.Void) { + push(kind.getStackKind(), x); + } + } + + /** + * Pops an instruction off the stack with the expected type. + * + * @param kind the expected type + * @return the instruction on the top of the stack + */ + public ValueNode pop(Kind kind) { + if (kind.needsTwoSlots()) { + xpop(); + } + assert assertPop(kind); + return xpop(); + } + + private boolean assertPop(Kind kind) { + assert kind != Kind.Void; + ValueNode x = xpeek(); + assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); + return true; + } + + /** + * Pops a value off of the stack without checking the type. + * + * @return x the instruction popped off the stack + */ + public ValueNode xpop() { + return stack[--stackSize]; + } + + public ValueNode xpeek() { + return stack[stackSize - 1]; + } + + /** + * Pops a value off of the stack and checks that it is an int. + * + * @return x the instruction popped off the stack + */ + public ValueNode ipop() { + assert assertIntPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a float. + * + * @return x the instruction popped off the stack + */ + public ValueNode fpop() { + assert assertFloatPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is an object. + * + * @return x the instruction popped off the stack + */ + public ValueNode apop() { + assert assertObjectPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a long. + * + * @return x the instruction popped off the stack + */ + public ValueNode lpop() { + assert assertHighPeek(); + xpop(); + assert assertLongPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a double. + * + * @return x the instruction popped off the stack + */ + public ValueNode dpop() { + assert assertHighPeek(); + xpop(); + assert assertDoublePeek(); + return xpop(); + } + + /** + * Pop the specified number of slots off of this stack and return them as an array of + * instructions. + * + * @return an array containing the arguments off of the stack + */ + public ValueNode[] popArguments(int argSize) { + ValueNode[] result = allocateArray(argSize); + int newStackSize = stackSize; + for (int i = argSize - 1; i >= 0; i--) { + newStackSize--; + if (stack[newStackSize] == null) { + /* Two-slot value. */ + newStackSize--; + assert stack[newStackSize].getKind().needsTwoSlots(); + } else { + assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1); + } + result[i] = stack[newStackSize]; + } + stackSize = newStackSize; + return result; + } + + /** + * Peeks an element from the operand stack. + * + * @param argumentNumber The number of the argument, relative from the top of the stack (0 = + * top). Long and double arguments only count as one argument, i.e., null-slots are + * ignored. + * @return The peeked argument. + */ + public ValueNode peek(int argumentNumber) { + int idx = stackSize() - 1; + for (int i = 0; i < argumentNumber; i++) { + if (stackAt(idx) == null) { + idx--; + assert stackAt(idx).getKind().needsTwoSlots(); + } + idx--; + } + return stackAt(idx); + } + + /** + * Clears all values on this stack. + */ + public void clearStack() { + stackSize = 0; + } + + private boolean assertLongPeek() { + return assertLong(xpeek()); + } + + private static boolean assertLong(ValueNode x) { + assert x != null && (x.getKind() == Kind.Long); + return true; + } + + private boolean assertIntPeek() { + return assertInt(xpeek()); + } + + private static boolean assertInt(ValueNode x) { + assert x != null && (x.getKind() == Kind.Int); + return true; + } + + private boolean assertFloatPeek() { + return assertFloat(xpeek()); + } + + private static boolean assertFloat(ValueNode x) { + assert x != null && (x.getKind() == Kind.Float); + return true; + } + + private boolean assertObjectPeek() { + return assertObject(xpeek()); + } + + private boolean assertObject(ValueNode x) { + assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object)); + return true; + } + + private boolean assertDoublePeek() { + return assertDouble(xpeek()); + } + + private static boolean assertDouble(ValueNode x) { + assert x != null && (x.getKind() == Kind.Double); + return true; + } + + private boolean assertHighPeek() { + assert xpeek() == null; + return true; + } + + @Override + public int hashCode() { + int result = hashCode(locals, locals.length); + result *= 13; + result += hashCode(stack, this.stackSize); + return result; + } + + private static int hashCode(Object[] a, int length) { + int result = 1; + for (int i = 0; i < length; ++i) { + Object element = a[i]; + result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); + } + return result; + } + + private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { + for (int i = 0; i < length; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + @Override + public boolean equals(Object otherObject) { + if (otherObject instanceof FrameStateBuilder) { + FrameStateBuilder other = (FrameStateBuilder) otherObject; + if (!other.method.equals(method)) { + return false; + } + if (other.stackSize != stackSize) { + return false; + } + if (other.parser != parser) { + return false; + } + if (other.rethrowException != rethrowException) { + return false; + } + if (other.graph != graph) { + return false; + } + if (other.locals.length != locals.length) { + return false; + } + return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && + equals(other.monitorIds, monitorIds, monitorIds.length); + } + return false; + } + + public void replace(ValueNode oldValue, ValueNode newValue) { + for (int i = 0; i < locals.length; i++) { + if (locals[i] == oldValue) { + locals[i] = newValue; + } + } + for (int i = 0; i < stackSize; i++) { + if (stack[i] == oldValue) { + stack[i] = newValue; + } + } + } + + @Override + public boolean isAfterSideEffect() { + return sideEffects != null; + } + + @Override + public Iterable sideEffects() { + return sideEffects; + } + + @Override + public void addSideEffect(StateSplit sideEffect) { + assert sideEffect != null; + assert sideEffect.hasSideEffect(); + if (sideEffects == null) { + sideEffects = new ArrayList<>(4); + } + sideEffects.add(sideEffect); + } +} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu May 28 17:44:05 2015 +0200 @@ -22,13 +22,15 @@ */ package com.oracle.graal.java; +import static com.oracle.graal.api.code.TypeCheckHints.*; import static com.oracle.graal.api.meta.DeoptimizationAction.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.compiler.common.GraalInternalError.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.common.type.StampFactory.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.nodes.StructuredGraph.*; import static com.oracle.graal.nodes.type.StampTool.*; import static java.lang.String.*; @@ -52,6 +54,7 @@ import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; +import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; @@ -61,6 +64,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; @@ -69,6 +73,125 @@ */ public class GraphBuilderPhase extends BasePhase { + public static class Options { + // @formatter:off + @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) + public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); + + @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(false); + + @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineIntrinsicsDuringParsing = new StableOptionValue<>(true); + + @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); + + @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); + + @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); + + @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); + + @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) + public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); + + @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) + public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); + + @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) + public static final OptionValue HideSubstitutionStates = new OptionValue<>(false); + + // @formatter:on + } + + /** + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * bytecode instructions as they are parsed. + */ + public static final int TRACELEVEL_INSTRUCTIONS = 1; + + /** + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * frame state before each bytecode instruction as it is parsed. + */ + public static final int TRACELEVEL_STATE = 2; + + /** + * Meters the number of actual bytecodes parsed. + */ + public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed"); + + /** + * Gets the kind of array elements for the array type code that appears in a + * {@link Bytecodes#NEWARRAY} bytecode. + * + * @param code the array type code + * @return the kind from the array type code + */ + public static Class arrayTypeCodeToClass(int code) { + // Checkstyle: stop + switch (code) { + case 4: + return boolean.class; + case 5: + return char.class; + case 6: + return float.class; + case 7: + return double.class; + case 8: + return byte.class; + case 9: + return short.class; + case 10: + return int.class; + case 11: + return long.class; + default: + throw new IllegalArgumentException("unknown array type code: " + code); + } + // Checkstyle: resume + } + + protected static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); + + protected static boolean allPositive(double[] a) { + for (double d : a) { + if (d < 0) { + return false; + } + } + return true; + } + + /** + * Helper function that sums up the probabilities of all keys that lead to a specific successor. + * + * @return an array of size successorCount with the accumulated probability for each successor. + */ + public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { + double[] probability = new double[successorCount]; + for (int i = 0; i < keySuccessors.length; i++) { + probability[keySuccessors[i]] += keyProbabilities[i]; + } + return probability; + } + + static class SuccessorInfo { + + int blockIndex; + int actualIndex; + + public SuccessorInfo(int blockSuccessorIndex) { + this.blockIndex = blockSuccessorIndex; + actualIndex = -1; + } + } + private final GraphBuilderConfiguration graphBuilderConfig; public GraphBuilderPhase(GraphBuilderConfiguration config) { @@ -84,6 +207,103 @@ return graphBuilderConfig; } + /** + * A scoped object for tasks to be performed after parsing an intrinsic such as processing + * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states. + */ + static class IntrinsicScope implements AutoCloseable { + FrameState stateBefore; + final Mark mark; + final BytecodeParser parser; + + /** + * Creates a scope for root parsing an intrinsic. + * + * @param parser the parsing context of the intrinsic + */ + public IntrinsicScope(BytecodeParser parser) { + this.parser = parser; + assert parser.parent == null; + assert parser.bci() == 0; + mark = null; + } + + /** + * Creates a scope for parsing an intrinsic during graph builder inlining. + * + * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic + * @param args the arguments to the call + */ + public IntrinsicScope(BytecodeParser parser, ValueNode[] args) { + assert !parser.parsingIntrinsic(); + this.parser = parser; + mark = parser.getGraph().getMark(); + stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, args); + } + + public void close() { + IntrinsicContext intrinsic = parser.intrinsicContext; + if (intrinsic != null && intrinsic.isPostParseInlined()) { + return; + } + + processPlaceholderFrameStates(intrinsic); + } + + /** + * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states + * added to the graph while parsing/inlining the intrinsic for which this object exists. + */ + private void processPlaceholderFrameStates(IntrinsicContext intrinsic) { + FrameState stateAfterReturn = null; + StructuredGraph graph = parser.getGraph(); + for (Node node : graph.getNewNodes(mark)) { + if (node instanceof FrameState) { + FrameState frameState = (FrameState) node; + if (BytecodeFrame.isPlaceholderBci(frameState.bci)) { + if (frameState.bci == BytecodeFrame.AFTER_BCI) { + FrameStateBuilder frameStateBuilder = parser.frameState; + if (frameState.stackSize() != 0) { + assert frameState.usages().count() == 1; + ValueNode returnVal = frameState.stackAt(0); + assert returnVal == frameState.usages().first(); + + /* + * Swap the top-of-stack value with the side-effect return value + * using the frame state. + */ + ValueNode tos = frameStateBuilder.pop(returnVal.getKind()); + assert tos.getKind() == returnVal.getKind(); + FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, returnVal); + frameState.replaceAndDelete(newFrameState); + frameStateBuilder.push(tos.getKind(), tos); + } else { + if (stateAfterReturn == null) { + if (intrinsic != null) { + assert intrinsic.isCompilationRoot(); + stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); + } else { + stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null); + } + } + frameState.replaceAndDelete(stateAfterReturn); + } + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { + if (stateBefore == null) { + stateBefore = graph.start().stateAfter(); + } + if (stateBefore != frameState) { + frameState.replaceAndDelete(stateBefore); + } + } else { + assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; + } + } + } + } + } + } + // Fully qualified name is a workaround for JDK-8056066 public static class Instance extends com.oracle.graal.phases.Phase { @@ -91,7 +311,7 @@ private final MetaAccessProvider metaAccess; - private final ReplacementContext initialReplacementContext; + private final IntrinsicContext initialIntrinsicContext; private final GraphBuilderConfiguration graphBuilderConfig; private final OptimisticOptimizations optimisticOpts; @@ -99,13 +319,13 @@ private final ConstantReflectionProvider constantReflection; public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { + OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; this.stampProvider = stampProvider; this.constantReflection = constantReflection; - this.initialReplacementContext = initialReplacementContext; + this.initialIntrinsicContext = initialIntrinsicContext; assert metaAccess != null; } @@ -118,12 +338,15 @@ this.graph = graph; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { - ReplacementContext replacementContext = initialReplacementContext; - BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext); - HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); - frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); - parser.build(graph.start(), frameState); - + IntrinsicContext intrinsicContext = initialIntrinsicContext; + BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, intrinsicContext); + FrameStateBuilder frameState = new FrameStateBuilder(parser, method, graph); + + frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); + + try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(parser) : null) { + parser.build(graph.start(), frameState); + } GraphUtil.normalizeLoops(graph); // Remove dead parameters. @@ -193,9 +416,9 @@ private static class Target { FixedNode fixed; - HIRFrameStateBuilder state; - - public Target(FixedNode fixed, HIRFrameStateBuilder state) { + FrameStateBuilder state; + + public Target(FixedNode fixed, FrameStateBuilder state) { this.fixed = fixed; this.state = state; } @@ -219,7 +442,7 @@ } } - public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { + public class BytecodeParser implements GraphBuilderContext { private BciBlockMapping blockMap; private LocalLiveness liveness; @@ -240,24 +463,32 @@ private FixedWithNextNode lastInstr; // the last instruction added private final boolean explodeLoops; private final boolean mergeExplosions; - private final Map mergeExplosionsMap; + private final Map mergeExplosionsMap; private Deque explodeLoopsContext; private int nextPeelIteration = 1; private boolean controlFlowSplit; private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); private FixedWithNextNode[] firstInstructionArray; - private HIRFrameStateBuilder[] entryStateArray; + private FrameStateBuilder[] entryStateArray; private FixedWithNextNode[][] firstInstructionMatrix; - private HIRFrameStateBuilder[][] entryStateMatrix; + private FrameStateBuilder[][] entryStateMatrix; public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts, int entryBCI, ReplacementContext replacementContext) { - super(metaAccess, method, graphBuilderConfig, optimisticOpts, replacementContext); + OptimisticOptimizations optimisticOpts, int entryBCI, IntrinsicContext intrinsicContext) { + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; + this.metaAccess = metaAccess; + this.stream = new BytecodeStream(method.getCode()); + this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null); + this.constantPool = method.getConstantPool(); + this.method = method; + this.intrinsicContext = intrinsicContext; + assert metaAccess != null; this.entryBCI = entryBCI; this.parent = parent; - if (graphBuilderConfig.insertNonSafepointDebugInfo()) { + if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) { lnt = method.getLineNumberTable(); previousLineNumber = -1; } @@ -295,7 +526,7 @@ return this.beforeUnwindNode; } - protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) { + protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) { if (PrintProfilingInformation.getValue() && profilingInfo != null) { TTY.println("Profiling info for " + method.format("%H.%n(%p)")); TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), " ")); @@ -307,15 +538,13 @@ BciBlockMapping newMapping = BciBlockMapping.create(stream, method); this.blockMap = newMapping; this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()]; - this.entryStateArray = new HIRFrameStateBuilder[blockMap.getBlockCount()]; - - if (graphBuilderConfig.doLivenessAnalysis()) { - try (Scope s = Debug.scope("LivenessAnalysis")) { - int maxLocals = method.getMaxLocals(); - liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); - } catch (Throwable e) { - throw Debug.handle(e); - } + this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()]; + + try (Scope s = Debug.scope("LivenessAnalysis")) { + int maxLocals = method.getMaxLocals(); + liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); + } catch (Throwable e) { + throw Debug.handle(e); } lastInstr = startInstruction; @@ -326,11 +555,27 @@ if (startInstruction == graph.start()) { StartNode startNode = graph.start(); if (method.isSynchronized()) { - startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI)); + assert !parsingIntrinsic(); + startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode)); } else { - frameState.clearNonLiveLocals(startBlock, liveness, true); - assert bci() == 0; - startNode.setStateAfter(createFrameState(bci())); + if (!parsingIntrinsic()) { + if (graph.method() != null && graph.method().isJavaLangObjectInit()) { + /* + * Don't clear the receiver when Object. is the + * compilation root. The receiver is needed as input to + * RegisterFinalizerNode. + */ + } else { + frameState.clearNonLiveLocals(startBlock, liveness, true); + } + assert bci() == 0; + startNode.setStateAfter(createFrameState(bci(), startNode)); + } else { + if (startNode.stateAfter() == null) { + FrameState stateAfterStart = createStateAfterStartOfReplacementGraph(); + startNode.setStateAfter(stateAfterStart); + } + } } } @@ -342,7 +587,7 @@ genMonitorEnter(methodSynchronizedObject, bci()); } - if (graphBuilderConfig.insertNonSafepointDebugInfo()) { + if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) { append(createInfoPointNode(InfopointReason.METHOD_START)); } @@ -372,6 +617,42 @@ } } + /** + * Creates the frame state after the start node of a graph for an + * {@link IntrinsicContext intrinsic} that is the parse root (either for root compiling + * or for post-parse inlining). + */ + private FrameState createStateAfterStartOfReplacementGraph() { + assert parent == null; + assert frameState.method.equals(intrinsicContext.getIntrinsicMethod()); + assert bci() == 0; + assert frameState.stackSize == 0; + FrameState stateAfterStart; + if (intrinsicContext.isPostParseInlined()) { + stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + ResolvedJavaMethod original = intrinsicContext.getOriginalMethod(); + ValueNode[] locals; + if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) { + locals = frameState.locals; + } else { + locals = new ValueNode[original.getMaxLocals()]; + int parameterCount = original.getSignature().getParameterCount(!original.isStatic()); + for (int i = 0; i < parameterCount; i++) { + ValueNode param = frameState.locals[i]; + locals[i] = param; + assert param == null || param instanceof ParameterNode || param.isConstant(); + } + } + ValueNode[] stack = {}; + int stackSize = 0; + ValueNode[] locks = {}; + List monitorIds = Collections.emptyList(); + stateAfterStart = graph.add(new FrameState(null, original, 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } + return stateAfterStart; + } + private void detectLoops(FixedNode startInstruction) { NodeBitMap visited = graph.createNodeBitMap(); NodeBitMap active = graph.createNodeBitMap(); @@ -404,7 +685,7 @@ } LoopBeginNode loopBegin = (LoopBeginNode) ((EndNode) merge.next()).merge(); LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); - if (parsingReplacement()) { + if (parsingIntrinsic()) { loopEnd.disableSafepoint(); } endNode.replaceAndDelete(loopEnd); @@ -566,7 +847,7 @@ return header.loopEnd + 1; } - private void addToMergeCache(HIRFrameStateBuilder key, int dimension) { + private void addToMergeCache(FrameStateBuilder key, int dimension) { mergeExplosionsMap.put(key, dimension); } @@ -605,7 +886,6 @@ /** * @param type the unresolved type of the constant */ - @Override protected void handleUnresolvedLoadConstant(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -615,7 +895,6 @@ * @param type the unresolved type of the type check * @param object the object value whose type is being checked against {@code type} */ - @Override protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { assert !graphBuilderConfig.eagerResolving(); append(new FixedGuardNode(graph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile)); @@ -626,7 +905,6 @@ * @param type the unresolved type of the type check * @param object the object value whose type is being checked against {@code type} */ - @Override protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { assert !graphBuilderConfig.eagerResolving(); AbstractBeginNode successor = graph.add(new BeginNode()); @@ -639,7 +917,6 @@ /** * @param type the type being instantiated */ - @Override protected void handleUnresolvedNewInstance(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -649,7 +926,6 @@ * @param type the type of the array being instantiated * @param length the length of the array */ - @Override protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -659,7 +935,6 @@ * @param type the type being instantiated * @param dims the dimensions for the multi-array */ - @Override protected void handleUnresolvedNewMultiArray(JavaType type, List dims) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -670,7 +945,6 @@ * @param receiver the object containing the field or {@code null} if {@code field} is * static */ - @Override protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -682,7 +956,6 @@ * @param receiver the object containing the field or {@code null} if {@code field} is * static */ - @Override protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -691,7 +964,6 @@ /** * @param type */ - @Override protected void handleUnresolvedExceptionType(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -720,7 +992,7 @@ dispatchBlock = blockMap.getUnwindBlock(); } - HIRFrameStateBuilder dispatchState = frameState.copy(); + FrameStateBuilder dispatchState = frameState.copy(); dispatchState.clearStack(); DispatchBeginNode dispatchBegin; @@ -728,11 +1000,11 @@ dispatchBegin = graph.add(new ExceptionObjectNode(metaAccess)); dispatchState.apush(dispatchBegin); dispatchState.setRethrowException(true); - dispatchBegin.setStateAfter(dispatchState.create(bci)); + dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin)); } else { dispatchBegin = graph.add(new DispatchBeginNode()); dispatchState.apush(exceptionObject); - dispatchBegin.setStateAfter(dispatchState.create(bci)); + dispatchBegin.setStateAfter(dispatchState.create(bci, dispatchBegin)); dispatchState.setRethrowException(true); } this.controlFlowSplit = true; @@ -742,148 +1014,119 @@ return dispatchBegin; } - @Override protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, Kind kind) { return LoadIndexedNode.create(array, index, kind, metaAccess, constantReflection); } - @Override protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) { add(new StoreIndexedNode(array, index, kind, value)); } - @Override - protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) { return AddNode.create(x, y); } - @Override - protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerSub(ValueNode x, ValueNode y) { return SubNode.create(x, y); } - @Override - protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerMul(ValueNode x, ValueNode y) { return MulNode.create(x, y); } - @Override - protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatAdd(ValueNode x, ValueNode y) { return AddNode.create(x, y); } - @Override - protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatSub(ValueNode x, ValueNode y) { return SubNode.create(x, y); } - @Override - protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatMul(ValueNode x, ValueNode y) { return MulNode.create(x, y); } - @Override - protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatDiv(ValueNode x, ValueNode y) { return DivNode.create(x, y); } - @Override - protected ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatRem(ValueNode x, ValueNode y) { return new RemNode(x, y); } - @Override - protected ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) { return new IntegerDivNode(x, y); } - @Override - protected ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerRem(ValueNode x, ValueNode y) { return new IntegerRemNode(x, y); } - @Override protected ValueNode genNegateOp(ValueNode x) { return (new NegateNode(x)); } - @Override - protected ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genLeftShift(ValueNode x, ValueNode y) { return new LeftShiftNode(x, y); } - @Override - protected ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genRightShift(ValueNode x, ValueNode y) { return new RightShiftNode(x, y); } - @Override - protected ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) { return new UnsignedRightShiftNode(x, y); } - @Override - protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genAnd(ValueNode x, ValueNode y) { return AndNode.create(x, y); } - @Override - protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genOr(ValueNode x, ValueNode y) { return OrNode.create(x, y); } - @Override - protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genXor(ValueNode x, ValueNode y) { return XorNode.create(x, y); } - @Override protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection); } - @Override protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { return FloatConvertNode.create(op, input); } - @Override protected ValueNode genNarrow(ValueNode input, int bitCount) { return NarrowNode.create(input, bitCount); } - @Override protected ValueNode genSignExtend(ValueNode input, int bitCount) { return SignExtendNode.create(input, bitCount); } - @Override protected ValueNode genZeroExtend(ValueNode input, int bitCount) { return ZeroExtendNode.create(input, bitCount); } - @Override protected void genGoto() { appendGoto(currentBlock.getSuccessor(0)); assert currentBlock.numNormalSuccessors() == 1; } - @Override protected LogicNode genObjectEquals(ValueNode x, ValueNode y) { return ObjectEqualsNode.create(x, y, constantReflection); } - @Override protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) { return IntegerEqualsNode.create(x, y, constantReflection); } - @Override protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) { return IntegerLessThanNode.create(x, y, constantReflection); } - @Override protected ValueNode genUnique(ValueNode x) { return (ValueNode) graph.unique((Node & ValueNumberable) x); } @@ -892,49 +1135,40 @@ return new IfNode(condition, falseSuccessor, trueSuccessor, d); } - @Override protected void genThrow() { ValueNode exception = frameState.apop(); append(new FixedGuardNode(graph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); lastInstr.setNext(handleException(exception, bci())); } - @Override protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) { return CheckCastNode.create(type, object, profileForTypeCheck, forStoreCheck, graph.getAssumptions()); } - @Override protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) { return InstanceOfNode.create(type, object, profileForTypeCheck); } - @Override protected ValueNode genConditional(ValueNode x) { return new ConditionalNode((LogicNode) x); } - @Override protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { return new NewInstanceNode(type, fillContents); } - @Override protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) { return new NewArrayNode(elementType, length, fillContents); } - @Override protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, List dimensions) { return new NewMultiArrayNode(type, dimensions.toArray(new ValueNode[0])); } - @Override protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { return new LoadFieldNode(receiver, field); } - @Override protected ValueNode emitExplicitNullCheck(ValueNode receiver) { if (StampTool.isPointerNonNull(receiver.stamp())) { return receiver; @@ -946,32 +1180,29 @@ append(new IfNode(graph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01)); lastInstr = falseSucc; - exception.setStateAfter(createFrameState(bci())); + exception.setStateAfter(createFrameState(bci(), exception)); exception.setNext(handleException(exception, bci())); return nonNullReceiver; } - @Override protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = graph.add(new BeginNode()); BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); lastInstr = trueSucc; - exception.setStateAfter(createFrameState(bci())); + exception.setStateAfter(createFrameState(bci(), exception)); exception.setNext(handleException(exception, bci())); } - @Override protected ValueNode genArrayLength(ValueNode x) { return ArrayLengthNode.create(x, constantReflection); } - @Override protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); append(storeFieldNode); - storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI())); + storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode)); } /** @@ -990,7 +1221,6 @@ return false; } - @Override protected void genInvokeStatic(JavaMethod target) { if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; @@ -1006,7 +1236,6 @@ } } - @Override protected void genInvokeInterface(JavaMethod target) { if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); @@ -1016,7 +1245,6 @@ } } - @Override protected void genInvokeDynamic(JavaMethod target) { if (target instanceof ResolvedJavaMethod) { JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); @@ -1030,7 +1258,6 @@ } } - @Override protected void genInvokeVirtual(JavaMethod target) { if (callTargetIsResolved(target)) { /* @@ -1057,7 +1284,6 @@ } - @Override protected void genInvokeSpecial(JavaMethod target) { if (callTargetIsResolved(target)) { assert target != null; @@ -1071,6 +1297,16 @@ private InvokeKind currentInvokeKind; private JavaType currentInvokeReturnType; + protected FrameStateBuilder frameState; + protected BciBlock currentBlock; + protected final BytecodeStream stream; + protected final GraphBuilderConfiguration graphBuilderConfig; + protected final ResolvedJavaMethod method; + protected final ProfilingInfo profilingInfo; + protected final OptimisticOptimizations optimisticOpts; + protected final ConstantPool constantPool; + protected final MetaAccessProvider metaAccess; + protected final IntrinsicContext intrinsicContext; public InvokeKind getInvokeKind() { return currentInvokeKind; @@ -1104,7 +1340,7 @@ } JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); - if (graphBuilderConfig.eagerResolving() || parsingReplacement()) { + if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) { returnType = returnType.resolve(targetMethod.getDeclaringClass()); } if (invokeKind.hasReceiver()) { @@ -1210,8 +1446,8 @@ for (Node n : newNodes) { if (n instanceof StateSplit) { StateSplit stateSplit = (StateSplit) n; - assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(), - targetMethod.format("%H.%n(%p)"), stateSplit); + assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s", + StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit); } } try { @@ -1231,9 +1467,8 @@ InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); if (plugin != null) { - ReplacementContext context = this.replacementContext; - if (context != null && context.isCallToOriginal(targetMethod)) { - // Self recursive replacement means the original + if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { + // Self recursive intrinsic means the original // method should be called. assert !targetMethod.hasBytecodes() : "TODO: when does this happen?"; return false; @@ -1256,69 +1491,56 @@ private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, JavaType returnType) { InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin(); - boolean canBeInlined = parsingReplacement() || targetMethod.canBeInlined(); + boolean canBeInlined = parsingIntrinsic() || targetMethod.canBeInlined(); if (plugin == null || !canBeInlined) { return false; } InlineInfo inlineInfo = plugin.getInlineInfo(this, targetMethod, args, returnType); if (inlineInfo != null) { - return inline(plugin, targetMethod, inlineInfo.methodToInline, inlineInfo.isReplacement, inlineInfo.isIntrinsic, args); + return inline(plugin, targetMethod, inlineInfo.methodToInline, inlineInfo.isIntrinsic, args); } return false; } public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) { - boolean res = inline(null, targetMethod, substitute, true, true, args); + boolean res = inline(null, targetMethod, substitute, true, args); assert res : "failed to inline " + substitute; } - private boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean isReplacement, boolean isIntrinsic, ValueNode[] args) { - int bci = bci(); + private boolean inline(InlineInvokePlugin plugin, ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean isIntrinsic, ValueNode[] args) { if (TraceInlineDuringParsing.getValue() || TraceParserPlugins.getValue()) { if (targetMethod.equals(inlinedMethod)) { traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)")); } else { - traceWithContext("inlining call to %s as replacement for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)")); + traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)")); } } - ReplacementContext context = this.replacementContext; - if (context != null && context.isCallToOriginal(targetMethod)) { - IntrinsicContext intrinsic = context.asIntrinsic(); - if (intrinsic != null) { - if (intrinsic.isCompilationRoot()) { - // A root compiled intrinsic needs to deoptimize - // if the slow path is taken - DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); - deopt.setStateBefore(intrinsic.getInvokeStateBefore(graph, null)); - return true; - } else { - // Otherwise inline the original method. Any frame state created - // during the inlining will exclude frame(s) in the - // intrinsic method (see HIRFrameStateBuilder.create(int bci)). - parseAndInlineCallee(context.method, args, null); - return true; - } + IntrinsicContext intrinsic = this.intrinsicContext; + if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken. During frame state + // assignment, the deopt node will get its stateBefore + // from the start node of the intrinsic + append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + return true; } else { - // Self recursive replacement means the original - // method should be called. - if (context.method.hasBytecodes()) { - parseAndInlineCallee(context.method, args, null); - return true; - } else { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + if (intrinsic.getOriginalMethod().isNative()) { return false; } + parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null); + return true; } } else { - if (context == null && isReplacement) { + if (intrinsic == null && isIntrinsic) { assert !inlinedMethod.equals(targetMethod); - if (isIntrinsic) { - context = new IntrinsicContext(targetMethod, inlinedMethod, args, bci); - } else { - context = new ReplacementContext(targetMethod, inlinedMethod); - } + intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, INLINE_DURING_PARSING); } if (inlinedMethod.hasBytecodes()) { - parseAndInlineCallee(inlinedMethod, args, context); + parseAndInlineCallee(inlinedMethod, args, intrinsic); if (plugin != null) { plugin.postInline(inlinedMethod); } @@ -1342,7 +1564,7 @@ * @param format a format string * @param args arguments to the format string */ - @Override + protected void traceWithContext(String format, Object... args) { StackTraceElement where = method.asStackTraceElement(bci()); TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(), @@ -1362,34 +1584,36 @@ return res; } - private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) { - BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext); - HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph); - if (!targetMethod.isStatic()) { - args[0] = nullCheckedValue(args[0]); - } - startFrameState.initializeFromArgumentsArray(args); - parser.build(this.lastInstr, startFrameState); - - FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); - this.lastInstr = calleeBeforeReturnNode; - if (calleeBeforeReturnNode != null) { - ValueNode calleeReturnValue = parser.getReturnValue(); - if (calleeReturnValue != null) { - frameState.push(targetMethod.getSignature().getReturnKind().getStackKind(), calleeReturnValue); + private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { + try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, args) : null) { + + BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); + FrameStateBuilder startFrameState = new FrameStateBuilder(parser, targetMethod, graph); + if (!targetMethod.isStatic()) { + args[0] = nullCheckedValue(args[0]); } - } - - FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); - if (calleeBeforeUnwindNode != null) { - ValueNode calleeUnwindValue = parser.getUnwindValue(); - assert calleeUnwindValue != null; - calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); - } - - // Record inlined method dependency in the graph - if (graph.isInlinedMethodRecordingEnabled()) { - graph.getInlinedMethods().add(targetMethod); + startFrameState.initializeFromArgumentsArray(args); + parser.build(this.lastInstr, startFrameState); + + FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); + this.lastInstr = calleeBeforeReturnNode; + Kind calleeReturnKind = targetMethod.getSignature().getReturnKind(); + if (calleeBeforeReturnNode != null) { + ValueNode calleeReturnValue = parser.getReturnValue(); + if (calleeReturnValue != null) { + frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue); + } + } + + FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); + if (calleeBeforeUnwindNode != null) { + ValueNode calleeUnwindValue = parser.getUnwindValue(); + assert calleeUnwindValue != null; + calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); + } + + // Record inlined method dependency in the graph + graph.recordInlinedMethod(targetMethod); } } @@ -1400,21 +1624,50 @@ protected InvokeNode createInvoke(CallTargetNode callTarget, Kind resultType) { InvokeNode invoke = append(new InvokeNode(callTarget, bci())); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI())); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, Kind resultType) { + if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) { + /* + * Clear non-live locals early so that the exception handler entry gets the + * cleared state. + */ + frameState.clearNonLiveLocals(currentBlock, liveness, false); + } + DispatchBeginNode exceptionEdge = handleException(null, bci()); InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI())); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } - @Override protected void genReturn(ValueNode returnVal, Kind returnKind) { - + if (parsingIntrinsic() && returnVal != null) { + if (returnVal instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) returnVal; + FrameState stateAfter = stateSplit.stateAfter(); + if (stateSplit.hasSideEffect()) { + assert stateSplit != null; + if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { + assert stateAfter.usages().count() == 1; + assert stateAfter.usages().first() == stateSplit; + stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal))); + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } else { + /* + * This must be the return value from within a partial + * intrinsification. + */ + assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci); + } + } else { + assert stateAfter == null; + } + } + } if (parent == null) { frameState.setRethrowException(false); frameState.clearStack(); @@ -1440,7 +1693,10 @@ } private void beforeReturn(ValueNode x, Kind kind) { - if (graphBuilderConfig.insertNonSafepointDebugInfo()) { + if (graph.method() != null && graph.method().isJavaLangObjectInit()) { + append(new RegisterFinalizerNode(frameState.localAt(0))); + } + if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) { append(createInfoPointNode(InfopointReason.METHOD_END)); } @@ -1450,15 +1706,13 @@ } } - @Override protected void genMonitorEnter(ValueNode x, int bci) { MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth())); MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId)); frameState.pushLock(x, monitorId); - monitorEnter.setStateAfter(createFrameState(bci)); + monitorEnter.setStateAfter(createFrameState(bci, monitorEnter)); } - @Override protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) { MonitorIdNode monitorId = frameState.peekMonitorId(); ValueNode lockedObject = frameState.popLock(); @@ -1466,10 +1720,9 @@ throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); } MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue)); - monitorExit.setStateAfter(createFrameState(bci)); + monitorExit.setStateAfter(createFrameState(bci, monitorExit)); } - @Override protected void genJsr(int dest) { BciBlock successor = currentBlock.getJsrSuccessor(); assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci(); @@ -1486,7 +1739,6 @@ appendGoto(successor); } - @Override protected void genRet(int localIndex) { BciBlock successor = currentBlock.getRetSuccessor(); ValueNode local = frameState.loadLocal(localIndex); @@ -1509,7 +1761,6 @@ return graph.unique(nextBciNode); } - @Override protected void genIntegerSwitch(ValueNode value, ArrayList actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { if (value.isConstant()) { JavaConstant constant = (JavaConstant) value.asConstant(); @@ -1531,7 +1782,6 @@ } } - @Override protected ConstantNode appendConstant(JavaConstant constant) { assert constant != null; return ConstantNode.forConstant(constant, metaAccess, graph); @@ -1574,7 +1824,7 @@ } } - private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { + private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) { if (currentBlock != null && !explodeLoops) { long exits = currentBlock.loops & ~targetBlock.loops; if (exits != 0) { @@ -1604,7 +1854,7 @@ if (targetBlock instanceof ExceptionDispatchBlock) { bci = ((ExceptionDispatchBlock) targetBlock).deoptBci; } - HIRFrameStateBuilder newState = state.copy(); + FrameStateBuilder newState = state.copy(); for (BciBlock loop : exitLoops) { LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop, this.getCurrentDimension()); LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); @@ -1617,7 +1867,7 @@ lastLoopExit = loopExit; Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop); newState.insertLoopProxies(loopExit, getEntryState(loop, this.getCurrentDimension())); - loopExit.setStateAfter(newState.create(bci)); + loopExit.setStateAfter(newState.create(bci, loopExit)); } lastLoopExit.setNext(target); @@ -1627,7 +1877,7 @@ return new Target(target, state); } - private HIRFrameStateBuilder getEntryState(BciBlock block, int dimension) { + private FrameStateBuilder getEntryState(BciBlock block, int dimension) { int id = block.id; if (dimension == 0) { return entryStateArray[id]; @@ -1636,9 +1886,9 @@ } } - private HIRFrameStateBuilder getEntryStateMultiDimension(int dimension, int id) { + private FrameStateBuilder getEntryStateMultiDimension(int dimension, int id) { if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) { - HIRFrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1]; + FrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1]; if (entryStateArrayEntry == null) { return null; } @@ -1648,7 +1898,7 @@ } } - private void setEntryState(BciBlock block, int dimension, HIRFrameStateBuilder entryState) { + private void setEntryState(BciBlock block, int dimension, FrameStateBuilder entryState) { int id = block.id; if (dimension == 0) { this.entryStateArray[id] = entryState; @@ -1657,9 +1907,9 @@ } } - private void setEntryStateMultiDimension(int dimension, HIRFrameStateBuilder entryState, int id) { + private void setEntryStateMultiDimension(int dimension, FrameStateBuilder entryState, int id) { if (entryStateMatrix == null) { - entryStateMatrix = new HIRFrameStateBuilder[4][]; + entryStateMatrix = new FrameStateBuilder[4][]; } if (dimension - 1 < entryStateMatrix.length) { // We are within bounds. @@ -1668,7 +1918,7 @@ entryStateMatrix = Arrays.copyOf(entryStateMatrix, Math.max(entryStateMatrix.length * 2, dimension)); } if (entryStateMatrix[dimension - 1] == null) { - entryStateMatrix[dimension - 1] = new HIRFrameStateBuilder[blockMap.getBlockCount()]; + entryStateMatrix[dimension - 1] = new FrameStateBuilder[blockMap.getBlockCount()]; } entryStateMatrix[dimension - 1][id] = entryState; } @@ -1719,7 +1969,7 @@ } } - private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { + private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1.01 : probability; if (isNeverExecutedCode(probability)) { return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); @@ -1729,11 +1979,11 @@ } } - private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) { + private FixedNode createTarget(BciBlock block, FrameStateBuilder state) { return createTarget(block, state, false, false); } - private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { + private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { assert block != null && state != null; assert !block.isExceptionEntry || state.stackSize() == 1; @@ -1755,7 +2005,7 @@ targetNode = getFirstInstruction(block, operatingDimension); Target target = checkLoopExit(targetNode, block, state); FixedNode result = target.fixed; - HIRFrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; + FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; setEntryState(block, operatingDimension, currentEntryState); currentEntryState.clearNonLiveLocals(block, liveness, true); @@ -1776,7 +2026,7 @@ */ LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block, operatingDimension); LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); - if (parsingReplacement()) { + if (parsingIntrinsic()) { loopEnd.disableSafepoint(); } Target target = checkLoopExit(loopEnd, block, state); @@ -1828,14 +2078,14 @@ return result; } - private int findOperatingDimension(BciBlock block, HIRFrameStateBuilder state) { + private int findOperatingDimension(BciBlock block, FrameStateBuilder state) { if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) { return findOperatingDimensionWithLoopExplosion(block, state); } return this.getCurrentDimension(); } - private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) { + private int findOperatingDimensionWithLoopExplosion(BciBlock block, FrameStateBuilder state) { for (ExplodedLoopContext context : explodeLoopsContext) { if (context.header == block) { @@ -1886,7 +2136,7 @@ * Returns a block begin node with the specified state. If the specified probability is * 0, the block deoptimizes immediately. */ - private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { + private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { FixedNode target = createTarget(probability, block, stateAfter); AbstractBeginNode begin = BeginNode.begin(target); @@ -1895,7 +2145,7 @@ return begin; } - private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) { + private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { if (target.isStatic()) { return appendConstant(target.getDeclaringClass().getJavaClass()); } else { @@ -1962,7 +2212,7 @@ if (block instanceof ExceptionDispatchBlock) { bci = ((ExceptionDispatchBlock) block).deoptBci; } - abstractMergeNode.setStateAfter(createFrameState(bci)); + abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode)); } } @@ -2034,7 +2284,6 @@ } } - @Override protected void iterateBytecodesForBlock(BciBlock block) { if (block.isLoopHeader && !explodeLoops) { // Create the loop header block, which later will merge the backward branches of @@ -2044,8 +2293,8 @@ lastInstr = loopBegin; // Create phi functions for all local variables and operand stack slots. - frameState.insertLoopPhis(liveness, block.loopId, loopBegin); - loopBegin.setStateAfter(createFrameState(block.startBci)); + frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis()); + loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin)); /* * We have seen all forward branches. All subsequent backward branches will @@ -2074,9 +2323,14 @@ int bci = block.startBci; BytecodesParsed.add(block.endBci - bci); + /* Reset line number for new block */ + if (graphBuilderConfig.insertSimpleDebugInfo()) { + previousLineNumber = -1; + } + while (bci < endBCI) { - if (graphBuilderConfig.insertNonSafepointDebugInfo() && lnt != null) { - currentLineNumber = lnt.getLineNumber(bci); + if (graphBuilderConfig.insertNonSafepointDebugInfo() && !parsingIntrinsic()) { + currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : (graphBuilderConfig.insertFullDebugInfo() ? -1 : bci); if (currentLineNumber != previousLineNumber) { append(createInfoPointNode(InfopointReason.LINE_NUMBER)); previousLineNumber = currentLineNumber; @@ -2093,7 +2347,7 @@ } EntryMarkerNode x = append(new EntryMarkerNode()); frameState.insertProxies(x); - x.setStateAfter(createFrameState(bci)); + x.setStateAfter(createFrameState(bci, x)); } try { @@ -2110,7 +2364,7 @@ bci = stream.currentBCI(); assert block == currentBlock; - assert !(lastInstr instanceof StateSplit) || lastInstr instanceof BeginNode || ((StateSplit) lastInstr).stateAfter() != null : lastInstr; + assert checkLastInstruction(); lastInstr = finishInstruction(lastInstr, frameState); if (bci < endBCI) { if (bci > block.endBci) { @@ -2124,6 +2378,23 @@ } } + /* Also a hook for subclasses. */ + protected boolean forceLoopPhis() { + return graph.isOSR(); + } + + protected boolean checkLastInstruction() { + if (lastInstr instanceof BeginNode) { + // ignore + } else if (lastInstr instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) lastInstr; + if (stateSplit.hasSideEffect()) { + assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter"; + } + } + return true; + } + private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { EndNode preLoopEnd = graph.add(new EndNode()); LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); @@ -2140,15 +2411,24 @@ * @param state The current frame state. * @return Returns the (new) last instruction. */ - protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) { + protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) { return instr; } private InfopointNode createInfoPointNode(InfopointReason reason) { if (graphBuilderConfig.insertFullDebugInfo()) { - return new FullInfopointNode(reason, createFrameState(bci())); + return new FullInfopointNode(reason, createFrameState(bci(), null)); } else { - return new SimpleInfopointNode(reason, new BytecodePosition(null, method, bci())); + BytecodePosition position = createBytecodePosition(); + // Update the previous infopoint position if no new fixed nodes were inserted + if (lastInstr instanceof SimpleInfopointNode) { + SimpleInfopointNode lastInfopoint = (SimpleInfopointNode) lastInstr; + if (lastInfopoint.getReason() == reason) { + lastInfopoint.setPosition(position); + return lastInfopoint; + } + } + return new SimpleInfopointNode(reason, position); } } @@ -2171,7 +2451,6 @@ } } - @Override protected void genIf(ValueNode x, Condition cond, ValueNode y) { assert currentBlock.getSuccessorCount() == 2; BciBlock trueBlock = currentBlock.getSuccessor(0); @@ -2247,7 +2526,7 @@ FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true); ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability); append(ifNode); - if (parsingReplacement()) { + if (parsingIntrinsic()) { if (x instanceof BranchProbabilityNode) { ((BranchProbabilityNode) x).simplify(null); } else if (y instanceof BranchProbabilityNode) { @@ -2377,8 +2656,8 @@ return parent; } - public Replacement getReplacement() { - return replacementContext; + public IntrinsicContext getIntrinsic() { + return intrinsicContext; } @Override @@ -2390,7 +2669,7 @@ if (bp != this) { fmt.format("%n%s", indent); } - fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement()); + fmt.format("%s [bci: %d, intrinsic: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingIntrinsic()); fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10)); bp = bp.parent; indent += " "; @@ -2399,21 +2678,964 @@ } public BailoutException bailout(String string) { - FrameState currentFrameState = createFrameState(bci()); + FrameState currentFrameState = createFrameState(bci(), null); StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState); BailoutException bailout = new BailoutException(string); throw GraphUtil.createBailoutException(string, bailout, elements); } - private FrameState createFrameState(int bci) { + private FrameState createFrameState(int bci, StateSplit forStateSplit) { if (currentBlock != null && bci > currentBlock.endBci) { frameState.clearNonLiveLocals(currentBlock, liveness, false); } - return frameState.create(bci); + return frameState.create(bci, forStateSplit); + } + + public void setStateAfter(StateSplit sideEffect) { + assert sideEffect.hasSideEffect(); + FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect); + sideEffect.setStateAfter(stateAfter); + } + + private BytecodePosition createBytecodePosition() { + return frameState.createBytecodePosition(bci()); + } + + public void setCurrentFrameState(FrameStateBuilder frameState) { + this.frameState = frameState; + } + + protected final BytecodeStream getStream() { + return stream; + } + + public int bci() { + return stream.currentBCI(); + } + + public void loadLocal(int index, Kind kind) { + frameState.push(kind, frameState.loadLocal(index)); + } + + public void storeLocal(Kind kind, int index) { + ValueNode value; + if (kind == Kind.Object) { + value = frameState.xpop(); + // astore and astore_ may be used to store a returnAddress (jsr) + assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind(); + } else { + value = frameState.pop(kind); + } + frameState.storeLocal(index, value, kind); + } + + private void genLoadConstant(int cpi, int opcode) { + Object con = lookupConstant(cpi, opcode); + + if (con instanceof JavaType) { + // this is a load of class constant which might be unresolved + JavaType type = (JavaType) con; + if (type instanceof ResolvedJavaType) { + frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass())); + } else { + handleUnresolvedLoadConstant(type); + } + } else if (con instanceof JavaConstant) { + JavaConstant constant = (JavaConstant) con; + frameState.push(constant.getKind().getStackKind(), appendConstant(constant)); + } else { + throw new Error("lookupConstant returned an object of incorrect type"); + } + } + + private void genLoadIndexed(Kind kind) { + ValueNode index = frameState.ipop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); + if (!tryLoadIndexedPlugin(kind, index, array)) { + frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); + } + } + + protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) { + LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin(); + if (loadIndexedPlugin != null && loadIndexedPlugin.apply(this, array, index, kind)) { + if (TraceParserPlugins.getValue()) { + traceWithContext("used load indexed plugin"); + } + return true; + } else { + return false; + } + } + + private void genStoreIndexed(Kind kind) { + ValueNode value = frameState.pop(kind.getStackKind()); + ValueNode index = frameState.ipop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); + genStoreIndexed(array, index, kind, value); + } + + private void stackOp(int opcode) { + switch (opcode) { + case DUP_X1: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP_X2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X1: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + ValueNode w4 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w4); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case SWAP: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + break; + } + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private void genArithmeticOp(Kind result, int opcode) { + ValueNode y = frameState.pop(result); + ValueNode x = frameState.pop(result); + ValueNode v; + switch (opcode) { + case IADD: + case LADD: + v = genIntegerAdd(x, y); + break; + case FADD: + case DADD: + v = genFloatAdd(x, y); + break; + case ISUB: + case LSUB: + v = genIntegerSub(x, y); + break; + case FSUB: + case DSUB: + v = genFloatSub(x, y); + break; + case IMUL: + case LMUL: + v = genIntegerMul(x, y); + break; + case FMUL: + case DMUL: + v = genFloatMul(x, y); + break; + case FDIV: + case DDIV: + v = genFloatDiv(x, y); + break; + case FREM: + case DREM: + v = genFloatRem(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(result, append(v)); + } + + private void genIntegerDivOp(Kind result, int opcode) { + ValueNode y = frameState.pop(result); + ValueNode x = frameState.pop(result); + ValueNode v; + switch (opcode) { + case IDIV: + case LDIV: + v = genIntegerDiv(x, y); + break; + case IREM: + case LREM: + v = genIntegerRem(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(result, append(v)); + } + + private void genNegateOp(Kind kind) { + frameState.push(kind, append(genNegateOp(frameState.pop(kind)))); + } + + private void genShiftOp(Kind kind, int opcode) { + ValueNode s = frameState.ipop(); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case ISHL: + case LSHL: + v = genLeftShift(x, s); + break; + case ISHR: + case LSHR: + v = genRightShift(x, s); + break; + case IUSHR: + case LUSHR: + v = genUnsignedRightShift(x, s); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genLogicOp(Kind kind, int opcode) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case IAND: + case LAND: + v = genAnd(x, y); + break; + case IOR: + case LOR: + v = genOr(x, y); + break; + case IXOR: + case LXOR: + v = genXor(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genCompareOp(Kind kind, boolean isUnorderedLess) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess))); + } + + private void genFloatConvert(FloatConvert op, Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(genFloatConvert(op, input))); + } + + private void genSignExtend(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount()))); + } + + private void genZeroExtend(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount()))); + } + + private void genNarrow(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount()))); + } + + private void genIncrement() { + int index = getStream().readLocalIndex(); + int delta = getStream().readIncrement(); + ValueNode x = frameState.loadLocal(index); + ValueNode y = appendConstant(JavaConstant.forInt(delta)); + frameState.storeLocal(index, append(genIntegerAdd(x, y))); + } + + private void genIfZero(Condition cond) { + ValueNode y = appendConstant(JavaConstant.INT_0); + ValueNode x = frameState.ipop(); + genIf(x, cond, y); + } + + private void genIfNull(Condition cond) { + ValueNode y = appendConstant(JavaConstant.NULL_POINTER); + ValueNode x = frameState.apop(); + genIf(x, cond, y); + } + + private void genIfSame(Kind kind, Condition cond) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + genIf(x, cond, y); + } + + protected JavaType lookupType(int cpi, int bytecode) { + maybeEagerlyResolve(cpi, bytecode); + JavaType result = constantPool.lookupType(cpi, bytecode); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; + return result; + } + + private JavaMethod lookupMethod(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaMethod result = constantPool.lookupMethod(cpi, opcode); + /* + * In general, one cannot assume that the declaring class being initialized is + * useful, since the actual concrete receiver may be a different class (except for + * static calls). Also, interfaces are initialized only under special circumstances, + * so that this assertion would often fail for interface calls. + */ + assert !graphBuilderConfig.unresolvedIsError() || + (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; + return result; + } + + private JavaField lookupField(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaField result = constantPool.lookupField(cpi, opcode); + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + return result; + } + + private Object lookupConstant(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + Object result = constantPool.lookupConstant(cpi); + assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + return result; + } + + private void maybeEagerlyResolve(int cpi, int bytecode) { + if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) { + constantPool.loadReferencedType(cpi, bytecode); + } + } + + private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { + if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { + return null; + } else { + return profilingInfo.getTypeProfile(bci()); + } + } + + private void genCheckCast() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, CHECKCAST); + ValueNode object = frameState.apop(); + if (type instanceof ResolvedJavaType) { + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) { + ValueNode checkCastNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + if (typeCheck.isTautology()) { + checkCastNode = object; + } else { + GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated, + DeoptimizationAction.InvalidateReprofile, StampFactory.exactNonNull(singleType))); + checkCastNode = piNode; + } + } + } + } + if (checkCastNode == null) { + checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + } + frameState.apush(checkCastNode); + } + } else { + handleUnresolvedCheckCast(type, object); + } + } + + private void genInstanceOf() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, INSTANCEOF); + ValueNode object = frameState.apop(); + if (type instanceof ResolvedJavaType) { + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) { + ValueNode instanceOfNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); + instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType)); + } + } + } + if (instanceOfNode == null) { + instanceOfNode = createInstanceOf(resolvedType, object, profile); + } + frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); + } + } else { + handleUnresolvedInstanceOf(type, object); + } + } + + void genNewInstance(int cpi) { + JavaType type = lookupType(cpi, NEW); + if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { + ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); + if (skippedExceptionTypes != null) { + for (ResolvedJavaType exceptionType : skippedExceptionTypes) { + if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) { + append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); + return; + } + } + } + frameState.apush(append(createNewInstance((ResolvedJavaType) type, true))); + } else { + handleUnresolvedNewInstance(type); + } + } + + private void genNewPrimitiveArray(int typeCode) { + Class clazz = arrayTypeCodeToClass(typeCode); + ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz); + frameState.apush(append(createNewArray(elementType, frameState.ipop(), true))); + } + + private void genNewObjectArray(int cpi) { + JavaType type = lookupType(cpi, ANEWARRAY); + ValueNode length = frameState.ipop(); + if (type instanceof ResolvedJavaType) { + frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true))); + } else { + handleUnresolvedNewObjectArray(type, length); + } + } - public FrameState createStateAfter() { - return createFrameState(stream.nextBCI()); + private void genNewMultiArray(int cpi) { + JavaType type = lookupType(cpi, MULTIANEWARRAY); + int rank = getStream().readUByte(bci() + 3); + List dims = new ArrayList<>(Collections.nCopies(rank, null)); + for (int i = rank - 1; i >= 0; i--) { + dims.set(i, frameState.ipop()); + } + if (type instanceof ResolvedJavaType) { + frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims))); + } else { + handleUnresolvedNewMultiArray(type, dims); + } + } + + private void genGetField(JavaField field) { + Kind kind = field.getKind(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); + if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { + appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); + } + } else { + handleUnresolvedLoadField(field, receiver); + } + } + + /** + * @param receiver the receiver of an object based operation + * @param index the index of an array based operation that is to be tested for out of + * bounds. This is null for a non-array operation. + * @return the receiver value possibly modified to have a tighter stamp + */ + protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { + assert receiver != null; + if (graphBuilderConfig.omitAllExceptionEdges() || + profilingInfo == null || + (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { + return receiver; + } + + ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); + if (index != null) { + ValueNode length = append(genArrayLength(nonNullReceiver)); + emitExplicitBoundsCheck(index, length); + } + EXPLICIT_EXCEPTIONS.increment(); + return nonNullReceiver; + } + + private void genPutField(JavaField field) { + ValueNode value = frameState.pop(field.getKind().getStackKind()); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); + if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + genStoreField(receiver, (ResolvedJavaField) field, value); + } else { + handleUnresolvedStoreField(field, value, receiver); + } + } + + private void genGetStatic(JavaField field) { + Kind kind = field.getKind(); + if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + // Javac does not allow use of "$assertionsDisabled" for a field name but + // Eclipse does in which case a suffix is added to the generated field. + if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { + appendOptimizedLoadField(kind, ConstantNode.forBoolean(true)); + return; + } + + LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) { + appendOptimizedLoadField(kind, genLoadField(null, resolvedField)); + } + } else { + handleUnresolvedLoadField(field, null); + } + } + + public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) { + return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field); + } + + private void genPutStatic(JavaField field) { + ValueNode value = frameState.pop(field.getKind().getStackKind()); + if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + genStoreField(null, (ResolvedJavaField) field, value); + } else { + handleUnresolvedStoreField(field, value, null); + } + } + + protected void appendOptimizedLoadField(Kind kind, ValueNode load) { + // append the load to the instruction + ValueNode optimized = append(load); + frameState.push(kind.getStackKind(), optimized); + } + + private double[] switchProbability(int numberOfCases, int bci) { + double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); + if (prob != null) { + assert prob.length == numberOfCases; + } else { + Debug.log("Missing probability (switch) in %s at bci %d", method, bci); + prob = new double[numberOfCases]; + for (int i = 0; i < numberOfCases; i++) { + prob[i] = 1.0d / numberOfCases; + } + } + assert allPositive(prob); + return prob; + } + + private void genSwitch(BytecodeSwitch bs) { + int bci = bci(); + ValueNode value = frameState.ipop(); + + int nofCases = bs.numberOfCases(); + double[] keyProbabilities = switchProbability(nofCases + 1, bci); + + Map bciToBlockSuccessorIndex = new HashMap<>(); + for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { + assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); + if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { + bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); + } + } + + ArrayList actualSuccessors = new ArrayList<>(); + int[] keys = new int[nofCases]; + int[] keySuccessors = new int[nofCases + 1]; + int deoptSuccessorIndex = -1; + int nextSuccessorIndex = 0; + boolean constantValue = value.isConstant(); + for (int i = 0; i < nofCases + 1; i++) { + if (i < nofCases) { + keys[i] = bs.keyAt(i); + } + + if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { + if (deoptSuccessorIndex < 0) { + deoptSuccessorIndex = nextSuccessorIndex++; + actualSuccessors.add(null); + } + keySuccessors[i] = deoptSuccessorIndex; + } else { + int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); + SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); + if (info.actualIndex < 0) { + info.actualIndex = nextSuccessorIndex++; + actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); + } + keySuccessors[i] = info.actualIndex; + } + } + + genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); + + } + + protected boolean isNeverExecutedCode(double probability) { + return probability == 0 && optimisticOpts.removeNeverExecutedCode(); + } + + protected double branchProbability() { + if (profilingInfo == null) { + return 0.5; + } + assert assertAtIfBytecode(); + double probability = profilingInfo.getBranchTakenProbability(bci()); + if (probability < 0) { + assert probability == -1 : "invalid probability"; + Debug.log("missing probability in %s at bci %d", method, bci()); + probability = 0.5; + } + + if (!optimisticOpts.removeNeverExecutedCode()) { + if (probability == 0) { + probability = 0.0000001; + } else if (probability == 1) { + probability = 0.999999; + } + } + return probability; + } + + private boolean assertAtIfBytecode() { + int bytecode = stream.currentBC(); + switch (bytecode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + case IFNULL: + case IFNONNULL: + return true; + } + assert false : String.format("%x is not an if bytecode", bytecode); + return true; + } + + public final void processBytecode(int bci, int opcode) { + int cpi; + + // Checkstyle: stop + // @formatter:off + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : frameState.xpop(); break; + case POP2 : frameState.xpop(); frameState.xpop(); break; + case DUP : frameState.xpush(frameState.xpeek()); break; + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; + case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; + case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; + case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; + case ARETURN : genReturn(frameState.apop(), Kind.Object); break; + case RETURN : genReturn(null, Kind.Void); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on + // Checkstyle: resume + } + + private void genArrayLength() { + frameState.ipush(append(genArrayLength(frameState.apop()))); + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + public FrameStateBuilder getFrameStateBuilder() { + return frameState; + } + + protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { + if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { + traceInstructionHelper(bci, opcode, blockStart); + } + return true; + } + + private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + if (!currentBlock.getJsrScope().isEmpty()) { + sb.append(' ').append(currentBlock.getJsrScope()); + } + Debug.log("%s", sb); + } + + public boolean parsingIntrinsic() { + return intrinsicContext != null; + } + + public BytecodeParser getNonIntrinsicAncestor() { + BytecodeParser ancestor = parent; + while (ancestor != null && ancestor.parsingIntrinsic()) { + ancestor = ancestor.parent; + } + return ancestor; } } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,973 +0,0 @@ -/* - * Copyright (c) 2012, 2015, 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.java; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.util.*; - -public final class HIRFrameStateBuilder { - - static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; - - protected final BytecodeParser parser; - protected final ResolvedJavaMethod method; - protected int stackSize; - protected final ValueNode[] locals; - protected final ValueNode[] stack; - protected ValueNode[] lockedObjects; - - /** - * @see BytecodeFrame#rethrowException - */ - protected boolean rethrowException; - - private MonitorIdNode[] monitorIds; - private final StructuredGraph graph; - private FrameState outerFrameState; - - /** - * Creates a new frame state builder for the given method and the given target graph. - * - * @param method the method whose frame is simulated - * @param graph the target graph of Graal nodes created by the builder - */ - public HIRFrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) { - this.parser = parser; - this.method = method; - this.locals = allocateArray(method.getMaxLocals()); - this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); - this.lockedObjects = allocateArray(0); - - assert graph != null; - - this.monitorIds = EMPTY_MONITOR_ARRAY; - this.graph = graph; - } - - public void initializeFromArgumentsArray(ValueNode[] arguments) { - - int javaIndex = 0; - int index = 0; - if (!method.isStatic()) { - // set the receiver - locals[javaIndex] = arguments[index]; - javaIndex = 1; - index = 1; - } - Signature sig = method.getSignature(); - int max = sig.getParameterCount(false); - for (int i = 0; i < max; i++) { - Kind kind = sig.getParameterKind(i); - locals[javaIndex] = arguments[index]; - javaIndex += kind.getSlotCount(); - index++; - } - } - - public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { - - int javaIndex = 0; - int index = 0; - if (!method.isStatic()) { - // add the receiver - FloatingNode receiver = null; - Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass()); - if (parameterPlugin != null) { - receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp); - } - if (receiver == null) { - receiver = new ParameterNode(javaIndex, receiverStamp); - } - locals[javaIndex] = graph.unique(receiver); - javaIndex = 1; - index = 1; - } - Signature sig = method.getSignature(); - int max = sig.getParameterCount(false); - ResolvedJavaType accessingClass = method.getDeclaringClass(); - for (int i = 0; i < max; i++) { - JavaType type = sig.getParameterType(i, accessingClass); - if (eagerResolve) { - type = type.resolve(accessingClass); - } - Kind kind = type.getKind(); - Stamp stamp; - if (kind == Kind.Object && type instanceof ResolvedJavaType) { - stamp = StampFactory.declared((ResolvedJavaType) type); - } else { - stamp = StampFactory.forKind(kind); - } - FloatingNode param = null; - if (parameterPlugin != null) { - param = parameterPlugin.interceptParameter(parser, index, stamp); - } - if (param == null) { - param = new ParameterNode(index, stamp); - } - locals[javaIndex] = graph.unique(param); - javaIndex += kind.getSlotCount(); - index++; - } - - if (parser.replacementContext instanceof IntrinsicContext) { - IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; - if (intrinsic.isCompilationRoot()) { - // Records the parameters to an root compiled intrinsic - intrinsic.args = locals.clone(); - } - } - } - - private HIRFrameStateBuilder(HIRFrameStateBuilder other) { - this.parser = other.parser; - this.method = other.method; - this.stackSize = other.stackSize; - this.locals = other.locals.clone(); - this.stack = other.stack.clone(); - this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); - this.rethrowException = other.rethrowException; - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - - assert other.graph != null; - graph = other.graph; - monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - assert lockedObjects.length == monitorIds.length; - } - - private static ValueNode[] allocateArray(int length) { - return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[locals: ["); - for (int i = 0; i < locals.length; i++) { - sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); - } - sb.append("] stack: ["); - for (int i = 0; i < stackSize; i++) { - sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); - } - sb.append("] locks: ["); - for (int i = 0; i < lockedObjects.length; i++) { - sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); - } - sb.append("]"); - if (rethrowException) { - sb.append(" rethrowException"); - } - sb.append("]"); - return sb.toString(); - } - - public FrameState create(int bci) { - BytecodeParser parent = parser.getParent(); - if (parser.parsingReplacement()) { - IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); - if (intrinsic != null) { - return intrinsic.getInvokeStateBefore(parser.getGraph(), parent); - } - } - // If this is the recursive call in a partial intrinsification - // the frame(s) of the intrinsic method are omitted - while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) { - parent = parent.getParent(); - } - return create(bci, parent, false); - } - - public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { - if (outerFrameState == null && parent != null) { - outerFrameState = parent.getFrameState().create(parent.bci()); - } - if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { - FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); - return newFrameState; - } - if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { - throw GraalInternalError.shouldNotReachHere(); - // return graph.add(new FrameState(bci)); - } - return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); - } - - public HIRFrameStateBuilder copy() { - return new HIRFrameStateBuilder(this); - } - - public boolean isCompatibleWith(HIRFrameStateBuilder other) { - assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; - assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; - - if (stackSize() != other.stackSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - ValueNode x = stackAt(i); - ValueNode y = other.stackAt(i); - if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) { - return false; - } - } - if (lockedObjects.length != other.lockedObjects.length) { - return false; - } - for (int i = 0; i < lockedObjects.length; i++) { - if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { - throw new BailoutException("unbalanced monitors"); - } - } - return true; - } - - public void merge(AbstractMergeNode block, HIRFrameStateBuilder other) { - assert isCompatibleWith(other); - - for (int i = 0; i < localsSize(); i++) { - ValueNode curLocal = localAt(i); - ValueNode mergedLocal = merge(curLocal, other.localAt(i), block); - if (curLocal != mergedLocal) { - storeLocal(i, mergedLocal); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode curStack = stackAt(i); - ValueNode mergedStack = merge(curStack, other.stackAt(i), block); - if (curStack != mergedStack) { - storeStack(i, mergedStack); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); - assert monitorIds[i] == other.monitorIds[i]; - } - } - - private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { - if (currentValue == null || currentValue.isDeleted()) { - return null; - } else if (block.isPhiAtMerge(currentValue)) { - if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { - propagateDelete((ValuePhiNode) currentValue); - return null; - } - ((PhiNode) currentValue).addInput(otherValue); - return currentValue; - } else if (currentValue != otherValue) { - assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); - if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { - return null; - } - return createValuePhi(currentValue, otherValue, block); - } else { - return currentValue; - } - } - - private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { - ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block)); - for (int i = 0; i < block.phiPredecessorCount(); i++) { - phi.addInput(currentValue); - } - phi.addInput(otherValue); - assert phi.valueCount() == block.phiPredecessorCount() + 1; - return phi; - } - - private void propagateDelete(FloatingNode node) { - assert node instanceof ValuePhiNode || node instanceof ProxyNode; - if (node.isDeleted()) { - return; - } - // Collect all phi functions that use this phi so that we can delete them recursively (after - // we delete ourselves to avoid circles). - List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot(); - - // Remove the phi function from all FrameStates where it is used and then delete it. - assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; - node.replaceAtUsages(null); - node.safeDelete(); - - for (FloatingNode phiUsage : propagateUsages) { - propagateDelete(phiUsage); - } - } - - public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin) { - for (int i = 0; i < localsSize(); i++) { - if (loopBegin.graph().isOSR() || liveness.localIsChangedInLoop(loopId, i)) { - storeLocal(i, createLoopPhi(loopBegin, localAt(i))); - } - } - for (int i = 0; i < stackSize(); i++) { - storeStack(i, createLoopPhi(loopBegin, stackAt(i))); - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]); - } - } - - public void insertLoopProxies(LoopExitNode loopExit, HIRFrameStateBuilder loopEntryState) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); - } - } - } - - public void insertProxies(AbstractBeginNode begin) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, begin, graph); - } - } - } - - private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value) { - if (value == null) { - return null; - } - assert !block.isPhiAtMerge(value) : "phi function for this block already created"; - - ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(value.stamp().unrestricted(), block)); - phi.addInput(value); - return phi; - } - - /** - * Adds a locked monitor to this frame state. - * - * @param object the object whose monitor will be locked. - */ - public void pushLock(ValueNode object, MonitorIdNode monitorId) { - assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object; - lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); - monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); - lockedObjects[lockedObjects.length - 1] = object; - monitorIds[monitorIds.length - 1] = monitorId; - assert lockedObjects.length == monitorIds.length; - } - - /** - * Removes a locked monitor from this frame state. - * - * @return the object whose monitor was removed from the locks list. - */ - public ValueNode popLock() { - try { - return lockedObjects[lockedObjects.length - 1]; - } finally { - lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); - monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); - assert lockedObjects.length == monitorIds.length; - } - } - - public MonitorIdNode peekMonitorId() { - return monitorIds[monitorIds.length - 1]; - } - - /** - * @return the current lock depth - */ - public int lockDepth() { - assert lockedObjects.length == monitorIds.length; - return lockedObjects.length; - } - - public boolean contains(ValueNode value) { - for (int i = 0; i < localsSize(); i++) { - if (localAt(i) == value) { - return true; - } - } - for (int i = 0; i < stackSize(); i++) { - if (stackAt(i) == value) { - return true; - } - } - assert lockedObjects.length == monitorIds.length; - for (int i = 0; i < lockedObjects.length; i++) { - if (lockedObjects[i] == value || monitorIds[i] == value) { - return true; - } - } - return false; - } - - public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { - /* - * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to - * remove it for normal compilations, but not for OSR compilations - otherwise dead object - * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with - * Kind.Illegal, because the conflicting branch might not have been parsed. - */ - if (liveness == null) { - return; - } - if (liveIn) { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveIn(block, i)) { - locals[i] = null; - } - } - } else { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveOut(block, i)) { - locals[i] = null; - } - } - } - } - - /** - * @see BytecodeFrame#rethrowException - */ - public boolean rethrowException() { - return rethrowException; - } - - /** - * @see BytecodeFrame#rethrowException - */ - public void setRethrowException(boolean b) { - rethrowException = b; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * Gets the value in the local variables at the specified index, without any sanity checking. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public ValueNode localAt(int i) { - return locals[i]; - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public ValueNode stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the lock at the specified index, without any sanity checking. - * - * @param i the index into the lock - * @return the instruction that produced the value for the specified lock - */ - public ValueNode lockAt(int i) { - return lockedObjects[i]; - } - - public void storeLock(int i, ValueNode lock) { - lockedObjects[i] = lock; - } - - /** - * Loads the local variable at the specified index, checking that the returned value is non-null - * and that two-stack values are properly handled. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public ValueNode loadLocal(int i) { - ValueNode x = locals[i]; - assert assertLoadLocal(i, x); - return x; - } - - private boolean assertLoadLocal(int i, ValueNode x) { - assert x != null : i; - assert parser.parsingReplacement() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); - assert parser.parsingReplacement() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); - return true; - } - - public void storeLocal(int i, ValueNode x) { - storeLocal(i, x, x == null ? null : x.getKind()); - } - - /** - * Stores a given local variable at the specified index. If the value occupies two slots, then - * the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, ValueNode x, Kind kind) { - assert assertStoreLocal(x); - locals[i] = x; - if (x != null) { - if (kind.needsTwoSlots() && !parser.parsingReplacement()) { - // if this is a double word, then kill i+1 - locals[i + 1] = null; - } - if (i > 0 && !parser.parsingReplacement()) { - ValueNode p = locals[i - 1]; - if (p != null && p.getKind().needsTwoSlots()) { - // if there was a double word at i - 1, then kill it - locals[i - 1] = null; - } - } - } - } - - private boolean assertStoreLocal(ValueNode x) { - assert x == null || parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; - return true; - } - - public void storeStack(int i, ValueNode x) { - assert assertStoreStack(i, x); - stack[i] = x; - } - - private boolean assertStoreStack(int i, ValueNode x) { - assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; - return true; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(Kind kind, ValueNode x) { - assert assertPush(kind, x); - xpush(x); - if (kind.needsTwoSlots()) { - xpush(null); - } - } - - private boolean assertPush(Kind kind, ValueNode x) { - assert parser.parsingReplacement() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); - assert x != null && (parser.parsingReplacement() || x.getKind() == kind); - return true; - } - - /** - * Pushes a value onto the stack without checking the type. - * - * @param x the instruction to push onto the stack - */ - public void xpush(ValueNode x) { - assert assertXpush(x); - stack[stackSize++] = x; - } - - private boolean assertXpush(ValueNode x) { - assert parser.parsingReplacement() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); - return true; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * - * @param x the instruction to push onto the stack - */ - public void ipush(ValueNode x) { - assert assertInt(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * - * @param x the instruction to push onto the stack - */ - public void fpush(ValueNode x) { - assert assertFloat(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * - * @param x the instruction to push onto the stack - */ - public void apush(ValueNode x) { - assert assertObject(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(ValueNode x) { - assert assertLong(x); - xpush(x); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * - * @param x the instruction to push onto the stack - */ - public void dpush(ValueNode x) { - assert assertDouble(x); - xpush(x); - xpush(null); - } - - public void pushReturn(Kind kind, ValueNode x) { - if (kind != Kind.Void) { - push(kind.getStackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public ValueNode pop(Kind kind) { - if (kind.needsTwoSlots()) { - xpop(); - } - assert assertPop(kind); - return xpop(); - } - - private boolean assertPop(Kind kind) { - assert kind != Kind.Void; - ValueNode x = xpeek(); - assert x != null && (parser.parsingReplacement() || x.getKind() == kind); - return true; - } - - /** - * Pops a value off of the stack without checking the type. - * - * @return x the instruction popped off the stack - */ - public ValueNode xpop() { - return stack[--stackSize]; - } - - public ValueNode xpeek() { - return stack[stackSize - 1]; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * - * @return x the instruction popped off the stack - */ - public ValueNode ipop() { - assert assertIntPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * - * @return x the instruction popped off the stack - */ - public ValueNode fpop() { - assert assertFloatPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * - * @return x the instruction popped off the stack - */ - public ValueNode apop() { - assert assertObjectPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * - * @return x the instruction popped off the stack - */ - public ValueNode lpop() { - assert assertHighPeek(); - xpop(); - assert assertLongPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * - * @return x the instruction popped off the stack - */ - public ValueNode dpop() { - assert assertHighPeek(); - xpop(); - assert assertDoublePeek(); - return xpop(); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of - * instructions. - * - * @return an array containing the arguments off of the stack - */ - public ValueNode[] popArguments(int argSize) { - ValueNode[] result = allocateArray(argSize); - int newStackSize = stackSize; - for (int i = argSize - 1; i >= 0; i--) { - newStackSize--; - if (stack[newStackSize] == null) { - /* Two-slot value. */ - newStackSize--; - assert stack[newStackSize].getKind().needsTwoSlots(); - } else { - assert parser.parsingReplacement() || (stack[newStackSize].getKind().getSlotCount() == 1); - } - result[i] = stack[newStackSize]; - } - stackSize = newStackSize; - return result; - } - - /** - * Peeks an element from the operand stack. - * - * @param argumentNumber The number of the argument, relative from the top of the stack (0 = - * top). Long and double arguments only count as one argument, i.e., null-slots are - * ignored. - * @return The peeked argument. - */ - public ValueNode peek(int argumentNumber) { - int idx = stackSize() - 1; - for (int i = 0; i < argumentNumber; i++) { - if (stackAt(idx) == null) { - idx--; - assert stackAt(idx).getKind().needsTwoSlots(); - } - idx--; - } - return stackAt(idx); - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackSize = 0; - } - - private boolean assertLongPeek() { - return assertLong(xpeek()); - } - - private static boolean assertLong(ValueNode x) { - assert x != null && (x.getKind() == Kind.Long); - return true; - } - - private boolean assertIntPeek() { - return assertInt(xpeek()); - } - - private static boolean assertInt(ValueNode x) { - assert x != null && (x.getKind() == Kind.Int); - return true; - } - - private boolean assertFloatPeek() { - return assertFloat(xpeek()); - } - - private static boolean assertFloat(ValueNode x) { - assert x != null && (x.getKind() == Kind.Float); - return true; - } - - private boolean assertObjectPeek() { - return assertObject(xpeek()); - } - - private boolean assertObject(ValueNode x) { - assert x != null && (parser.parsingReplacement() || (x.getKind() == Kind.Object)); - return true; - } - - private boolean assertDoublePeek() { - return assertDouble(xpeek()); - } - - private static boolean assertDouble(ValueNode x) { - assert x != null && (x.getKind() == Kind.Double); - return true; - } - - private boolean assertHighPeek() { - assert xpeek() == null; - return true; - } - - @Override - public int hashCode() { - int result = hashCode(locals, locals.length); - result *= 13; - result += hashCode(stack, this.stackSize); - return result; - } - - private static int hashCode(Object[] a, int length) { - int result = 1; - for (int i = 0; i < length; ++i) { - Object element = a[i]; - result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); - } - return result; - } - - private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { - for (int i = 0; i < length; ++i) { - if (a[i] != b[i]) { - return false; - } - } - return true; - } - - @Override - public boolean equals(Object otherObject) { - if (otherObject instanceof HIRFrameStateBuilder) { - HIRFrameStateBuilder other = (HIRFrameStateBuilder) otherObject; - if (!other.method.equals(method)) { - return false; - } - if (other.stackSize != stackSize) { - return false; - } - if (other.parser != parser) { - return false; - } - if (other.rethrowException != rethrowException) { - return false; - } - if (other.graph != graph) { - return false; - } - if (other.locals.length != locals.length) { - return false; - } - return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && - equals(other.monitorIds, monitorIds, monitorIds.length); - } - return false; - } - - public void replace(ValueNode oldValue, ValueNode newValue) { - for (int i = 0; i < locals.length; i++) { - if (locals[i] == oldValue) { - locals[i] = newValue; - } - } - for (int i = 0; i < stackSize; i++) { - if (stack[i] == oldValue) { - stack[i] = newValue; - } - } - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/IntrinsicContext.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2015, 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.java; - -import static com.oracle.graal.java.HIRFrameStateBuilder.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.java.GraphBuilderPhase.Instance.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a compiler - * intrinsic must replay the intrinsified call. This context object retains the information required - * to build a frame state denoting the JVM state just before the intrinsified call. - */ -public class IntrinsicContext extends ReplacementContext { - - /** - * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed. - */ - public static final int POST_PARSE_INLINE_BCI = -1; - - /** - * BCI denoting an intrinsic is the compilation root. - */ - public static final int ROOT_COMPILATION_BCI = -2; - - /** - * The arguments to the intrinsic. - */ - ValueNode[] args; - - /** - * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or - * {@link #ROOT_COMPILATION_BCI}. - */ - final int bci; - - private FrameState stateBeforeCache; - - public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) { - super(method, substitute); - assert bci != POST_PARSE_INLINE_BCI || args == null; - this.args = args; - this.bci = bci; - assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)"); - } - - @Override - public boolean isIntrinsic() { - return true; - } - - public boolean isPostParseInlined() { - return bci == POST_PARSE_INLINE_BCI; - } - - public boolean isCompilationRoot() { - return bci == ROOT_COMPILATION_BCI; - } - - public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) { - if (isCompilationRoot()) { - int maxLocals = method.getMaxLocals(); - // The 'args' were initialized based on the intrinsic method but a - // frame state's 'locals' needs to have the same length as the frame - // state method's 'max_locals'. - ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals); - ValueNode[] stack = EMPTY_ARRAY; - int stackSize = 0; - ValueNode[] locks = EMPTY_ARRAY; - List monitorIds = Collections.emptyList(); - return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false)); - } else if (isPostParseInlined()) { - return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); - } else { - assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; - if (stateBeforeCache == null) { - - // Find the non-intrinsic ancestor calling the intrinsified method - BytecodeParser ancestor = parent; - while (ancestor.parsingReplacement()) { - assert ancestor.replacementContext instanceof IntrinsicContext; - ancestor = ancestor.getParent(); - } - FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); - stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args); - } - return stateBeforeCache; - } - } - - @Override - IntrinsicContext asIntrinsic() { - return this; - } - - @Override - public String toString() { - return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + (args == null ? "" : ", args: " + Arrays.toString(args)) + - (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}"; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.java/src/com/oracle/graal/java/ReplacementContext.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/ReplacementContext.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, 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.java; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; - -/** - * Information about a substitute method being parsed in lieu of an original method. This can happen - * when a call to a {@link MethodSubstitution} is encountered or the root of compilation is a - * {@link MethodSubstitution} or a snippet. - */ -public class ReplacementContext implements Replacement { - /** - * The method being replaced. - */ - final ResolvedJavaMethod method; - - /** - * The replacement method. - */ - final ResolvedJavaMethod replacement; - - public ReplacementContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute) { - this.method = method; - this.replacement = substitute; - } - - public ResolvedJavaMethod getOriginalMethod() { - return method; - } - - public ResolvedJavaMethod getReplacementMethod() { - return replacement; - } - - public boolean isIntrinsic() { - return false; - } - - /** - * Determines if a call within the compilation scope of a replacement represents a call to the - * original method. - */ - public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) { - return method.equals(targetMethod) || replacement.equals(targetMethod); - } - - IntrinsicContext asIntrinsic() { - return null; - } - - @Override - public String toString() { - return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}"; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Thu May 28 17:44:05 2015 +0200 @@ -44,6 +44,21 @@ } @Test + public void runFirst() throws Throwable { + /* + * Execute Double.isNaN enough times to create a profile indicating that the path returning + * false is never taken. Then compile and execute the test with a NaN value to test that + * deoptimization works in the case of an uncommon trap inlined into an intrinsic. Of + * course, this relies on Double.isNaN never having yet been called with NaN. if it has, + * this test is equivalent to run0. + */ + for (int i = 0; i < 10000; i++) { + Double.isNaN(1D); + } + executeActual(getResolvedJavaMethod("test"), null, java.lang.Double.NaN); + } + + @Test public void run0() throws Throwable { runTest("test", java.lang.Double.NaN); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Thu May 28 17:44:05 2015 +0200 @@ -67,7 +67,7 @@ } - @Test(timeout = 20000) + @Test public void run0() throws Throwable { runTest("test"); } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Thu May 28 17:44:05 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.lir.LIRInstruction.*; public final class AMD64AddressValue extends CompositeValue { - private static final long serialVersionUID = -4444600052487578694L; @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Thu May 28 17:44:05 2015 +0200 @@ -71,9 +71,13 @@ } @Opcode("CALL_DIRECT") - public abstract static class DirectCallOp extends MethodCallOp { + public static class DirectCallOp extends MethodCallOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectCallOp.class); + public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + this(TYPE, callTarget, result, parameters, temps, state); + } + protected DirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { super(c, callTarget, result, parameters, temps, state); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Thu May 28 17:44:05 2015 +0200 @@ -38,13 +38,12 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; -import com.oracle.graal.lir.amd64.AMD64Call.CallOp; import com.oracle.graal.lir.asm.*; public class AMD64ControlFlow { public static final class ReturnOp extends AMD64LIRInstruction implements BlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CallOp.class); + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ReturnOp.class); @Use({REG, ILLEGAL}) protected Value x; public ReturnOp(Value x) { diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,10 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.MoveOp; @@ -563,22 +566,23 @@ private static void const2stack(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, JavaConstant input) { assert !crb.codeCache.needsDataPatch(input); AMD64Address dest = (AMD64Address) crb.asAddress(result); + final long imm; switch (input.getKind().getStackKind()) { case Int: - masm.movl(dest, input.asInt()); + imm = input.asInt(); break; case Long: - masm.movlong(dest, input.asLong()); + imm = input.asLong(); break; case Float: - masm.movl(dest, floatToRawIntBits(input.asFloat())); + imm = floatToRawIntBits(input.asFloat()); break; case Double: - masm.movlong(dest, doubleToRawLongBits(input.asDouble())); + imm = doubleToRawLongBits(input.asDouble()); break; case Object: if (input.isNull()) { - masm.movlong(dest, 0L); + imm = 0; } else { throw GraalInternalError.shouldNotReachHere("Non-null object constants must be in register"); } @@ -586,5 +590,27 @@ default: throw GraalInternalError.shouldNotReachHere(); } + switch (result.getKind()) { + case Byte: + assert NumUtil.isByte(imm) : "Is not in byte range: " + imm; + AMD64MIOp.MOVB.emit(masm, OperandSize.BYTE, dest, (int) imm); + break; + case Short: + assert NumUtil.isShort(imm) : "Is not in short range: " + imm; + AMD64MIOp.MOV.emit(masm, OperandSize.WORD, dest, (int) imm); + break; + case Int: + case Float: + assert NumUtil.isInt(imm) : "Is not in int range: " + imm; + masm.movl(dest, (int) imm); + break; + case Long: + case Double: + case Object: + masm.movlong(dest, imm); + break; + default: + throw GraalInternalError.shouldNotReachHere("Unknown result Kind: " + result.getKind()); + } } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java --- a/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/LIRTest.java Thu May 28 17:44:05 2015 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver; import com.oracle.graal.jtt.*; @@ -49,26 +48,30 @@ */ public abstract class LIRTest extends JTTTest { - protected abstract static class LIRTestSpecification { + public abstract static class LIRTestSpecification { private Value result; - void generate(LIRGeneratorTool gen, Value arg0) { + public void generate(LIRGeneratorTool gen) { + defaultHandler(gen); + } + + public void generate(LIRGeneratorTool gen, Value arg0) { defaultHandler(gen, arg0); } - void generate(LIRGeneratorTool gen, Value arg0, Value arg1) { + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1) { defaultHandler(gen, arg0, arg1); } - void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) { + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2) { defaultHandler(gen, arg0, arg1, arg2); } - void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) { + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3) { defaultHandler(gen, arg0, arg1, arg2, arg3); } - void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) { + public void generate(LIRGeneratorTool gen, Value arg0, Value arg1, Value arg2, Value arg3, Value arg4) { defaultHandler(gen, arg0, arg1, arg2, arg3, arg4); } @@ -77,7 +80,9 @@ } void generate(LIRGeneratorTool gen, Value[] values) { - if (values.length == 1) { + if (values.length == 0) { + generate(gen); + } else if (values.length == 1) { generate(gen, values[0]); } else if (values.length == 2) { generate(gen, values[0], values[1]); @@ -142,7 +147,7 @@ } @NodeInfo - private static final class FloatingLIRTestNode extends FloatingNode implements LIRLowerable, Simplifiable { + private static final class FloatingLIRTestNode extends FloatingNode implements LIRLowerable { public static final NodeClass TYPE = NodeClass.create(FloatingLIRTestNode.class); @Input protected ValueNode opsNode; @@ -165,13 +170,6 @@ } @Override - public void simplify(SimplifierTool tool) { - if (tool.allUsagesAvailable() && getLIROpsNode().isConstant()) { - getLIROpsNode().asConstant(); - } - } - - @Override public void generate(NodeLIRBuilderTool gen) { LIRTestSpecification ops = getLIROperations(); Stream v = values().stream().map(node -> gen.operand(node)); @@ -252,7 +250,7 @@ assert Modifier.isStatic(m.getModifiers()); Class[] p = m.getParameterTypes(); assert p.length > 0; - assert p[0].equals(LIRTestSpecification.class); + assert LIRTestSpecification.class.isAssignableFrom(p[0]); if (m.getReturnType().equals(void.class)) { invocationPlugins.register(fixedLIRNodePlugin, c, m.getName(), p); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java Thu May 28 17:44:05 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.lir.LIRInstruction.OperandMode; public final class SPARCAddressValue extends CompositeValue { - private static final long serialVersionUID = -3583286416638228207L; @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base; @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Thu May 28 17:44:05 2015 +0200 @@ -90,7 +90,7 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegReg.class); @Opcode private final SPARCArithmetic opcode; - @Def({REG, HINT}) protected Value result; + @Def({REG}) protected Value result; @Use({REG}) protected Value x; @Alive({REG}) protected Value y; @State LIRFrameState state; @@ -127,7 +127,7 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BinaryRegConst.class); @Opcode private final SPARCArithmetic opcode; - @Def({REG, HINT}) protected AllocatableValue result; + @Def({REG}) protected AllocatableValue result; @Use({REG}) protected Value x; @State protected LIRFrameState state; protected JavaConstant y; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java Thu May 28 17:44:05 2015 +0200 @@ -133,6 +133,7 @@ * Emits code that uses 8-byte vector compares. */ private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert lengthValue.getPlatformKind().equals(Kind.Int); Label loop = new Label(); Label compareTail = new Label(); Label compareTailCorrectVectorEnd = new Label(); @@ -142,6 +143,7 @@ boolean hasCBcond = masm.hasFeature(CPUFeature.CBCOND); + masm.sra(length, 0, length); masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes) masm.andcc(length, ~(VECTOR_SIZE - 1), length); // vector count (in bytes) masm.bpcc(ConditionFlag.Equal, NOT_ANNUL, compareTail, CC.Xcc, PREDICT_NOT_TAKEN); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Thu May 28 17:44:05 2015 +0200 @@ -31,7 +31,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; @@ -280,16 +281,15 @@ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { try (ScratchRegister scratchReg = masm.getScratchRegister()) { Register scratch = scratchReg.getRegister(); - StackSlot intInput = reInterprete(asStackSlot(getInput())); - StackSlot intResult = reInterprete(asStackSlot(getResult())); + StackSlot intInput = reInterpret(asStackSlot(getInput())); + StackSlot intResult = reInterpret(asStackSlot(getResult())); // move stack slot move(crb, masm, scratch.asValue(intInput.getLIRKind()), intInput, SPARCDelayedControlTransfer.DUMMY); move(crb, masm, intResult, scratch.asValue(intResult.getLIRKind()), delayedControlTransfer); } - } - private static StackSlot reInterprete(StackSlot slot) { + private static StackSlot reInterpret(StackSlot slot) { switch ((Kind) slot.getPlatformKind()) { case Boolean: case Byte: @@ -343,52 +343,21 @@ public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); @Def({REG}) protected AllocatableValue result; + protected boolean signExtend; public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) { + this(kind, result, address, state, false); + } + + public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state, boolean signExtend) { super(TYPE, kind, address, state); this.result = result; + this.signExtend = signExtend; } @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - final SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); - final Register dst = asRegister(result); - delayedControlTransfer.emitControlTransfer(crb, masm); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - switch ((Kind) kind) { - case Boolean: - case Byte: - masm.ldsb(addr, dst); - break; - case Short: - masm.ldsh(addr, dst); - break; - case Char: - masm.lduh(addr, dst); - break; - case Int: - masm.ldsw(addr, dst); - break; - case Long: - masm.ldx(addr, dst); - break; - case Float: - masm.ldf(addr, dst); - break; - case Double: - masm.lddf(addr, dst); - break; - case Object: - masm.ldx(addr, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } + emitLoad(address.toAddress(), result, signExtend, kind, delayedControlTransfer, state, crb, masm); } } @@ -433,7 +402,7 @@ } } - public static final class MembarOp extends SPARCLIRInstruction { + public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MembarOp.class); private final int barriers; @@ -445,6 +414,7 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + delayedControlTransfer.emitControlTransfer(crb, masm); masm.membar(barriers); } } @@ -452,10 +422,10 @@ public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(NullCheckOp.class); - @Use({REG}) protected AllocatableValue input; + @Use({COMPOSITE}) protected SPARCAddressValue input; @State protected LIRFrameState state; - public NullCheckOp(Variable input, LIRFrameState state) { + public NullCheckOp(SPARCAddressValue input, LIRFrameState state) { super(TYPE); this.input = input; this.state = state; @@ -464,8 +434,9 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { delayedControlTransfer.emitControlTransfer(crb, masm); + SPARCAddress addr = input.toAddress(); crb.recordImplicitException(masm.position(), state); - masm.ldx(new SPARCAddress(asRegister(input), 0), g0); + masm.ldx(addr, g0); } public Value getCheckedValue() { @@ -496,8 +467,8 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - move(crb, masm, result, newValue, delayedControlTransfer); - compareAndSwap(masm, address, cmpValue, result); + move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY); + compareAndSwap(crb, masm, address, cmpValue, result, delayedControlTransfer); } } @@ -550,42 +521,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert isRegister(input); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); - delayedControlTransfer.emitControlTransfer(crb, masm); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - switch ((Kind) kind) { - case Boolean: - case Byte: - masm.stb(asRegister(input), addr); - break; - case Short: - case Char: - masm.sth(asRegister(input), addr); - break; - case Int: - masm.stw(asRegister(input), addr); - break; - case Long: - masm.stx(asRegister(input), addr); - break; - case Object: - masm.stx(asRegister(input), addr); - break; - case Float: - masm.stf(asRegister(input), addr); - break; - case Double: - masm.stdf(asRegister(input), addr); - break; - default: - throw GraalInternalError.shouldNotReachHere("missing: " + kind); - } - } + emitStore(input, address.toAddress(), kind, delayedControlTransfer, state, crb, masm); } } @@ -642,13 +578,15 @@ if (isRegister(result)) { reg2reg(crb, masm, result, input, delaySlotLir); } else if (isStackSlot(result)) { - reg2stack(crb, masm, result, input, delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(input, resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { throw GraalInternalError.shouldNotReachHere(); } } else if (isStackSlot(input)) { if (isRegister(result)) { - stack2reg(crb, masm, result, input, delaySlotLir); + SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); + emitLoad(inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { throw GraalInternalError.shouldNotReachHere(); } @@ -658,7 +596,8 @@ const2reg(crb, masm, result, constant, delaySlotLir); } else if (isStackSlot(result)) { if (constant.isDefaultForKind() || constant.isNull()) { - reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)), delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(g0.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); @@ -668,7 +607,8 @@ } else { new Setx(value, scratch).emit(masm); } - reg2stack(crb, masm, result, scratch.asValue(LIRKind.derive(input)), delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(scratch.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } } } else { @@ -735,78 +675,6 @@ } } - private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { - SPARCAddress dst = (SPARCAddress) crb.asAddress(result); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - dst = generateSimm13OffsetLoad(dst, masm, scratch); - Register src = asRegister(input); - delaySlotLir.emitControlTransfer(crb, masm); - switch (input.getKind()) { - case Byte: - case Boolean: - masm.stb(src, dst); - break; - case Char: - case Short: - masm.sth(src, dst); - break; - case Int: - masm.stw(src, dst); - break; - case Long: - case Object: - masm.stx(src, dst); - break; - case Float: - masm.stf(src, dst); - break; - case Double: - masm.stdf(src, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind() + "(" + input + ")"); - } - } - } - - private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { - SPARCAddress src = (SPARCAddress) crb.asAddress(input); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - src = generateSimm13OffsetLoad(src, masm, scratch); - Register dst = asRegister(result); - delaySlotLir.emitControlTransfer(crb, masm); - switch (input.getKind()) { - case Boolean: - case Byte: - masm.ldsb(src, dst); - break; - case Short: - masm.ldsh(src, dst); - break; - case Char: - masm.lduh(src, dst); - break; - case Int: - masm.ldsw(src, dst); - break; - case Long: - case Object: - masm.ldx(src, dst); - break; - case Float: - masm.ldf(src, dst); - break; - case Double: - masm.lddf(src, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind()); - } - } - } - private static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); @@ -912,7 +780,9 @@ } } - protected static void compareAndSwap(SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) { + protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue, + SPARCDelayedControlTransfer delay) { + delay.emitControlTransfer(crb, masm); switch (cmpValue.getKind()) { case Int: masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue)); @@ -925,4 +795,101 @@ throw GraalInternalError.shouldNotReachHere(); } } + + private static void emitLoad(SPARCAddress address, Value result, boolean signExtend, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, + CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); + final Register dst = asRegister(result); + delayedControlTransfer.emitControlTransfer(crb, masm); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + switch ((Kind) kind) { + case Boolean: + case Byte: + if (signExtend) { + masm.ldsb(addr, dst); + } else { + masm.ldub(addr, dst); + } + break; + case Short: + if (signExtend) { + masm.ldsh(addr, dst); + } else { + masm.lduh(addr, dst); + } + break; + case Char: + if (signExtend) { + masm.ldsh(addr, dst); + } else { + masm.lduh(addr, dst); + } + break; + case Int: + if (signExtend) { + masm.ldsw(addr, dst); + } else { + masm.lduw(addr, dst); + } + break; + case Long: + masm.ldx(addr, dst); + break; + case Float: + masm.ldf(addr, dst); + break; + case Double: + masm.lddf(addr, dst); + break; + case Object: + masm.ldx(addr, dst); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + private static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb, + SPARCMacroAssembler masm) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); + delayedControlTransfer.emitControlTransfer(crb, masm); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + switch ((Kind) kind) { + case Boolean: + case Byte: + masm.stb(asRegister(input), addr); + break; + case Short: + case Char: + masm.sth(asRegister(input), addr); + break; + case Int: + masm.stw(asRegister(input), addr); + break; + case Long: + masm.stx(asRegister(input), addr); + break; + case Object: + masm.stx(asRegister(input), addr); + break; + case Float: + masm.stf(asRegister(input), addr); + break; + case Double: + masm.stdf(asRegister(input), addr); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + kind); + } + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java --- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java Thu May 28 17:44:05 2015 +0200 @@ -43,7 +43,6 @@ private static class TestCompositeValue extends CompositeValue { - private static final long serialVersionUID = -8804214200173503527L; @Component({REG, OperandFlag.ILLEGAL}) protected Value value; public TestCompositeValue(Value value) { @@ -70,7 +69,6 @@ private static class DummyValue extends AbstractValue { - private static final long serialVersionUID = -645435039553382737L; private final int id; private static int counter = 1; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java Thu May 28 17:44:05 2015 +0200 @@ -37,8 +37,6 @@ */ public abstract class CompositeValue extends AbstractValue { - private static final long serialVersionUID = -169180052684126180L; - @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public static @interface Component { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java Thu May 28 17:44:05 2015 +0200 @@ -39,7 +39,7 @@ * such fields.

  • * */ -public final class CompositeValueClass { +public final class CompositeValueClass extends FieldIntrospection { /** * The CompositeValueClass is only used for formatting for the most part so cache it as a @@ -56,16 +56,15 @@ }; - public static CompositeValueClass get(Class type) { - return compositeClass.get(type); + @SuppressWarnings("unchecked") + public static CompositeValueClass get(Class type) { + return (CompositeValueClass) compositeClass.get(type); } - private final Class clazz; private final Values values; - private final Fields data; private CompositeValueClass(Class clazz) { - this.clazz = clazz; + super(clazz); CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset()); vfs.scan(clazz, CompositeValue.class, false); @@ -94,9 +93,14 @@ } @Override + public Fields[] getAllFields() { + return new Fields[]{data, values}; + } + + @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" components["); + str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components["); values.appendFields(str); str.append("] data["); data.appendFields(str); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Thu May 28 17:44:05 2015 +0200 @@ -76,6 +76,17 @@ } } + @SuppressWarnings("unchecked") + public static LIRInstructionClass get(Class clazz) { + try { + Field field = clazz.getDeclaredField("TYPE"); + field.setAccessible(true); + return (LIRInstructionClass) field.get(null); + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + private static class LIRInstructionFieldsScanner extends LIRFieldsScanner { private String opcodeConstant; @@ -137,7 +148,7 @@ if (STATE_CLASS.isAssignableFrom(type)) { assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; - states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type)); + states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass())); } else { super.scanField(field, offset); } @@ -151,6 +162,12 @@ } @Override + public Fields[] getAllFields() { + assert values == null; + return new Fields[]{data, uses, alives, temps, defs, states}; + } + + @Override public String toString() { StringBuilder str = new StringBuilder(); str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use["); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java Thu May 28 17:44:05 2015 +0200 @@ -100,8 +100,8 @@ final EnumSet flags; - public ValueFieldInfo(long offset, String name, Class type, EnumSet flags) { - super(offset, name, type); + public ValueFieldInfo(long offset, String name, Class type, Class declaringClass, EnumSet flags) { + super(offset, name, type, declaringClass); assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type); this.flags = flags; } @@ -171,14 +171,14 @@ assert annotation != null : "Field must have operand mode annotation: " + field; EnumSet flags = getFlags(field); assert verifyFlags(field, type, flags); - annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags)); + annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); annotation.directCount++; } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { OperandModeAnnotation annotation = getOperandModeAnnotation(field); assert annotation != null : "Field must have operand mode annotation: " + field; EnumSet flags = getFlags(field); assert verifyFlags(field, type.getComponentType(), flags); - annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags)); + annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); } else { assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Thu May 28 17:44:05 2015 +0200 @@ -31,8 +31,6 @@ */ public final class Variable extends AllocatableValue { - private static final long serialVersionUID = 4507578431686109809L; - /** * The identifier of the variable. This is a non-zero index in a contiguous 0-based name space. */ diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Thu May 28 17:44:05 2015 +0200 @@ -25,9 +25,7 @@ import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*; import static com.oracle.graal.lir.LIRValueUtil.*; -import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*; import java.util.*; @@ -36,20 +34,16 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.lir.*; import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.StandardOp.LabelOp; -import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.lir.alloc.lsra.Interval.RegisterBinding; -import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; -import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext; import com.oracle.graal.options.*; /** @@ -60,19 +54,18 @@ */ class LinearScan { - final TargetDescription target; final LIRGenerationResult res; final LIR ir; final FrameMapBuilder frameMapBuilder; - final SpillMoveFactory spillMoveFactory; final RegisterAttributes[] registerAttributes; final Register[] registers; final RegisterAllocationConfig regAllocConfig; + private final SpillMoveFactory moveFactory; final boolean callKillsRegisters; public static final int DOMINATOR_SPILL_MOVE_ID = -2; - private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1; + static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1; public static class Options { // @formatter:off @@ -113,52 +106,45 @@ public BitSet liveKill; } - final BlockMap blockData; + private final BlockMap blockData; /** * List of blocks in linear-scan order. This is only correct as long as the CFG does not change. */ final List> sortedBlocks; - /** - * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals. - */ - Interval[] intervals; + /** @see #intervals() */ + private Interval[] intervals; /** * The number of valid entries in {@link #intervals}. */ - int intervalsSize; + private int intervalsSize; /** * The index of the first entry in {@link #intervals} for a * {@linkplain #createDerivedInterval(Interval) derived interval}. */ - int firstDerivedIntervalIndex = -1; + private int firstDerivedIntervalIndex = -1; /** * Intervals sorted by {@link Interval#from()}. */ - Interval[] sortedIntervals; + private Interval[] sortedIntervals; /** * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. Entries should * be retrieved with {@link #instructionForId(int)} as the id is not simply an index into this * array. */ - LIRInstruction[] opIdToInstructionMap; + private LIRInstruction[] opIdToInstructionMap; /** * Map from an instruction {@linkplain LIRInstruction#id id} to the * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved * with {@link #blockForId(int)} as the id is not simply an index into this array. */ - AbstractBlockBase[] opIdToBlockMap; - - /** - * Bit set for each variable that is contained in each loop. - */ - BitMap2D intervalInLoop; + private AbstractBlockBase[] opIdToBlockMap; /** * The {@linkplain #operandNumber(Value) number} of the first variable operand allocated. @@ -166,10 +152,9 @@ private final int firstVariableNumber; LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) { - this.target = target; this.res = res; this.ir = res.getLIR(); - this.spillMoveFactory = spillMoveFactory; + this.moveFactory = spillMoveFactory; this.frameMapBuilder = res.getFrameMapBuilder(); this.sortedBlocks = ir.linearScanOrder(); this.registerAttributes = regAllocConfig.getRegisterConfig().getAttributesMap(); @@ -179,8 +164,10 @@ this.firstVariableNumber = registers.length; this.blockData = new BlockMap<>(ir.getControlFlowGraph()); - // If all allocatable registers are caller saved, then no registers are live across a call - // site. The register allocator can save time not trying to find a register at a call site. + /* + * If all allocatable registers are caller saved, then no registers are live across a call + * site. The register allocator can save time not trying to find a register at a call site. + */ this.callKillsRegisters = regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved(); } @@ -198,7 +185,7 @@ } SpillMoveFactory getSpillMoveFactory() { - return spillMoveFactory; + return moveFactory; } protected MoveResolver createMoveResolver() { @@ -216,7 +203,7 @@ * the {@linkplain Variable variables} and {@linkplain RegisterValue registers} being processed * by this allocator. */ - private int operandNumber(Value operand) { + int operandNumber(Value operand) { if (isRegister(operand)) { int number = asRegister(operand).number; assert number < firstVariableNumber; @@ -229,7 +216,7 @@ /** * Gets the number of operands. This value will increase by 1 for new variable. */ - private int operandSize() { + int operandSize() { return firstVariableNumber + ir.numVariables(); } @@ -240,6 +227,14 @@ return firstVariableNumber - 1; } + BlockData getBlockData(AbstractBlockBase block) { + return blockData.get(block); + } + + void initBlockData(AbstractBlockBase block) { + blockData.put(block, new BlockData()); + } + static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() { @Override @@ -273,8 +268,10 @@ } void assignSpillSlot(Interval interval) { - // assign the canonical spill slot of the parent (if a part of the interval - // is already spilled) or allocate a new spill slot + /* + * Assign the canonical spill slot of the parent (if a part of the interval is already + * spilled) or allocate a new spill slot. + */ if (interval.canMaterialize()) { interval.assignLocation(Value.ILLEGAL); } else if (interval.spillSlot() != null) { @@ -287,6 +284,18 @@ } /** + * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals. + */ + Interval[] intervals() { + return intervals; + } + + void initIntervals() { + intervalsSize = operandSize(); + intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)]; + } + + /** * Creates a new interval. * * @param operand the operand for the interval @@ -345,10 +354,6 @@ return ir.getControlFlowGraph().getLoops().size(); } - boolean isIntervalInLoop(int interval, int loop) { - return intervalInLoop.at(interval, loop); - } - Interval intervalFor(int operandNumber) { return intervals[operandNumber]; } @@ -368,6 +373,16 @@ } } + void initOpIdMaps(int numInstructions) { + opIdToInstructionMap = new LIRInstruction[numInstructions]; + opIdToBlockMap = new AbstractBlockBase[numInstructions]; + } + + void putOpIdMaps(int index, LIRInstruction op, AbstractBlockBase block) { + opIdToInstructionMap[index] = op; + opIdToBlockMap[index] = block; + } + /** * Gets the highest instruction id allocated by this object. */ @@ -378,10 +393,10 @@ /** * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR - * instructions in a method have an index one greater than their linear-scan order predecesor + * instructions in a method have an index one greater than their linear-scan order predecessor * with the first instruction having an index of 0. */ - static int opIdToIndex(int opId) { + private static int opIdToIndex(int opId) { return opId >> 1; } @@ -429,909 +444,15 @@ return instructionForId(opId).destroysCallerSavedRegisters(); } - /** - * Eliminates moves from register to stack if the stack slot is known to be correct. - */ - void changeSpillDefinitionPos(Interval interval, int defPos) { - assert interval.isSplitParent() : "can only be called for split parents"; - - switch (interval.spillState()) { - case NoDefinitionFound: - assert interval.spillDefinitionPos() == -1 : "must no be set before"; - interval.setSpillDefinitionPos(defPos); - interval.setSpillState(SpillState.NoSpillStore); - break; - - case NoSpillStore: - assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; - if (defPos < interval.spillDefinitionPos() - 2) { - // second definition found, so no spill optimization possible for this interval - interval.setSpillState(SpillState.NoOptimization); - } else { - // two consecutive definitions (because of two-operand LIR form) - assert blockForId(defPos) == blockForId(interval.spillDefinitionPos()) : "block must be equal"; - } - break; - - case NoOptimization: - // nothing to do - break; - - default: - throw new BailoutException("other states not allowed at this time"); - } - } - - // called during register allocation - void changeSpillState(Interval interval, int spillPos) { - switch (interval.spillState()) { - case NoSpillStore: { - int defLoopDepth = blockForId(interval.spillDefinitionPos()).getLoopDepth(); - int spillLoopDepth = blockForId(spillPos).getLoopDepth(); - - if (defLoopDepth < spillLoopDepth) { - // the loop depth of the spilling position is higher then the loop depth - // at the definition of the interval . move write to memory out of loop. - if (Options.LSRAOptimizeSpillPosition.getValue()) { - // find best spill position in dominator the tree - interval.setSpillState(SpillState.SpillInDominator); - } else { - // store at definition of the interval - interval.setSpillState(SpillState.StoreAtDefinition); - } - } else { - // the interval is currently spilled only once, so for now there is no - // reason to store the interval at the definition - interval.setSpillState(SpillState.OneSpillStore); - } - break; - } - - case OneSpillStore: { - if (Options.LSRAOptimizeSpillPosition.getValue()) { - // the interval is spilled more then once - interval.setSpillState(SpillState.SpillInDominator); - } else { - // it is better to store it to - // memory at the definition - interval.setSpillState(SpillState.StoreAtDefinition); - } - break; - } - - case SpillInDominator: - case StoreAtDefinition: - case StartInMemory: - case NoOptimization: - case NoDefinitionFound: - // nothing to do - break; - - default: - throw new BailoutException("other states not allowed at this time"); - } - } - abstract static class IntervalPredicate { abstract boolean apply(Interval i); } - private static final IntervalPredicate mustStoreAtDefinition = new IntervalPredicate() { - - @Override - public boolean apply(Interval i) { - return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition; - } - }; - - /** - * @return the index of the first instruction that is of interest for - * {@link #eliminateSpillMoves()} - */ - protected int firstInstructionOfInterest() { - // skip the first because it is always a label - return 1; - } - - // called once before assignment of register numbers - void eliminateSpillMoves() { - try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) { - - // collect all intervals that must be stored after their definition. - // the list is sorted by Interval.spillDefinitionPos - Interval interval; - interval = createUnhandledLists(mustStoreAtDefinition, null).first; - if (DetailedAsserts.getValue()) { - checkIntervals(interval); - } - - LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); - for (AbstractBlockBase block : sortedBlocks) { - try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) { - List instructions = ir.getLIRforBlock(block); - int numInst = instructions.size(); - - // iterate all instructions of the block. - for (int j = firstInstructionOfInterest(); j < numInst; j++) { - LIRInstruction op = instructions.get(j); - int opId = op.id(); - - if (opId == -1) { - MoveOp move = (MoveOp) op; - /* - * Remove move from register to stack if the stack slot is guaranteed to - * be correct. Only moves that have been inserted by LinearScan can be - * removed. - */ - if (canEliminateSpillMove(block, move)) { - /* - * Move target is a stack slot that is always correct, so eliminate - * instruction. - */ - if (Debug.isLogEnabled()) { - Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", operandNumber(move.getInput()), move.getInput(), operandNumber(move.getResult()), - move.getResult(), block); - } - - // null-instructions are deleted by assignRegNum - instructions.set(j, null); - } - - } else { - /* - * Insert move from register to stack just after the beginning of the - * interval. - */ - assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; - assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - - while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { - if (!interval.canMaterialize()) { - if (!insertionBuffer.initialized()) { - /* - * prepare insertion buffer (appended when all instructions - * in the block are processed) - */ - insertionBuffer.init(instructions); - } - - AllocatableValue fromLocation = interval.location(); - AllocatableValue toLocation = canonicalSpillOpr(interval); - if (!fromLocation.equals(toLocation)) { - - assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + - interval.spillState(); - assert isStackSlotValue(toLocation) : "to operand must be a stack slot"; - - LIRInstruction move = getSpillMoveFactory().createMove(toLocation, fromLocation); - insertionBuffer.append(j + 1, move); - - if (Debug.isLogEnabled()) { - Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); - } - } - } - interval = interval.next; - } - } - } // end of instruction iteration - - if (insertionBuffer.initialized()) { - insertionBuffer.finish(); - } - } - } // end of block iteration - - assert interval == Interval.EndMarker : "missed an interval"; - } - } - - /** - * @param block The block {@code move} is located in. - * @param move Spill move. - */ - protected boolean canEliminateSpillMove(AbstractBlockBase block, MoveOp move) { - assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move; - - Interval curInterval = intervalFor(move.getResult()); - - if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { - assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); - return true; - } - return false; - } - - private static void checkIntervals(Interval interval) { - Interval prev = null; - Interval temp = interval; - while (temp != Interval.EndMarker) { - assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos"; - if (prev != null) { - assert temp.from() >= prev.from() : "intervals not sorted"; - assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from : then they must also be sorted by spillDefinitionPos"; - } - - assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned"; - assert temp.spillDefinitionPos() >= temp.from() : "invalid order"; - assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized"; - - if (Debug.isLogEnabled()) { - Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos()); - } - - prev = temp; - temp = temp.next; - } - } - - /** - * Numbers all instructions in all blocks. The numbering follows the - * {@linkplain ComputeBlockOrder linear scan order}. - */ - void numberInstructions() { - - intervalsSize = operandSize(); - intervals = new Interval[intervalsSize + (intervalsSize >> SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT)]; - - ValueConsumer setVariableConsumer = (value, mode, flags) -> { - if (isVariable(value)) { - getOrCreateInterval(asVariable(value)); - } - }; - - // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. - int numInstructions = 0; - for (AbstractBlockBase block : sortedBlocks) { - numInstructions += ir.getLIRforBlock(block).size(); - } - - // initialize with correct length - opIdToInstructionMap = new LIRInstruction[numInstructions]; - opIdToBlockMap = new AbstractBlockBase[numInstructions]; - - int opId = 0; - int index = 0; - for (AbstractBlockBase block : sortedBlocks) { - blockData.put(block, new BlockData()); - - List instructions = ir.getLIRforBlock(block); - - int numInst = instructions.size(); - for (int j = 0; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - op.setId(opId); - - opIdToInstructionMap[index] = op; - opIdToBlockMap[index] = block; - assert instructionForId(opId) == op : "must match"; - - op.visitEachTemp(setVariableConsumer); - op.visitEachOutput(setVariableConsumer); - - index++; - opId += 2; // numbering of lirOps by two - } - } - assert index == numInstructions : "must match"; - assert (index << 1) == opId : "must match: " + (index << 1); - } - - /** - * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill}) - * separately for each block. - */ - void computeLocalLiveSets() { - int liveSize = liveSetSize(); - - intervalInLoop = new BitMap2D(operandSize(), numLoops()); - - // iterate all blocks - for (final AbstractBlockBase block : sortedBlocks) { - try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) { - - final BitSet liveGen = new BitSet(liveSize); - final BitSet liveKill = new BitSet(liveSize); - - List instructions = ir.getLIRforBlock(block); - int numInst = instructions.size(); - - ValueConsumer useConsumer = (operand, mode, flags) -> { - if (isVariable(operand)) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - if (Debug.isLogEnabled()) { - Debug.log("liveGen for operand %d(%s)", operandNum, operand); - } - } - if (block.getLoop() != null) { - intervalInLoop.setBit(operandNum, block.getLoop().getIndex()); - } - } - - if (DetailedAsserts.getValue()) { - verifyInput(block, liveKill, operand); - } - }; - ValueConsumer stateConsumer = (operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - if (Debug.isLogEnabled()) { - Debug.log("liveGen in state for operand %d(%s)", operandNum, operand); - } - } - } - }; - ValueConsumer defConsumer = (operand, mode, flags) -> { - if (isVariable(operand)) { - int varNum = operandNumber(operand); - liveKill.set(varNum); - if (Debug.isLogEnabled()) { - Debug.log("liveKill for operand %d(%s)", varNum, operand); - } - if (block.getLoop() != null) { - intervalInLoop.setBit(varNum, block.getLoop().getIndex()); - } - } - - if (DetailedAsserts.getValue()) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - verifyTemp(liveKill, operand); - } - }; - - // iterate all instructions of the block - for (int j = 0; j < numInst; j++) { - final LIRInstruction op = instructions.get(j); - - try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { - op.visitEachInput(useConsumer); - op.visitEachAlive(useConsumer); - // Add uses of live locals from interpreter's point of view for proper debug - // information generation - op.visitEachState(stateConsumer); - op.visitEachTemp(defConsumer); - op.visitEachOutput(defConsumer); - } - } // end of instruction iteration - - BlockData blockSets = blockData.get(block); - blockSets.liveGen = liveGen; - blockSets.liveKill = liveKill; - blockSets.liveIn = new BitSet(liveSize); - blockSets.liveOut = new BitSet(liveSize); - - if (Debug.isLogEnabled()) { - Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); - Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); - } - - } - } // end of block iteration - } - - private void verifyTemp(BitSet liveKill, Value operand) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - if (isRegister(operand)) { - if (isProcessed(operand)) { - liveKill.set(operandNumber(operand)); - } - } - } - - private void verifyInput(AbstractBlockBase block, BitSet liveKill, Value operand) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets. - // this is checked by these assertions to be sure about it. - // the entry block may have incoming - // values in registers, which is ok. - if (isRegister(operand) && block != ir.getControlFlowGraph().getStartBlock()) { - if (isProcessed(operand)) { - assert liveKill.get(operandNumber(operand)) : "using fixed register that is not defined in this block"; - } - } - } - - /** - * Performs a backward dataflow analysis to compute global live sets (i.e. - * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. - */ - void computeGlobalLiveSets() { - try (Indent indent = Debug.logAndIndent("compute global live sets")) { - int numBlocks = blockCount(); - boolean changeOccurred; - boolean changeOccurredInBlock; - int iterationCount = 0; - BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations - - // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. - // The loop is executed until a fixpoint is reached (no changes in an iteration) - do { - changeOccurred = false; - - try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { - - // iterate all blocks in reverse order - for (int i = numBlocks - 1; i >= 0; i--) { - AbstractBlockBase block = blockAt(i); - BlockData blockSets = blockData.get(block); - - changeOccurredInBlock = false; - - // liveOut(block) is the union of liveIn(sux), for successors sux of block - int n = block.getSuccessorCount(); - if (n > 0) { - liveOut.clear(); - // block has successors - if (n > 0) { - for (AbstractBlockBase successor : block.getSuccessors()) { - liveOut.or(blockData.get(successor).liveIn); - } - } - - if (!blockSets.liveOut.equals(liveOut)) { - // A change occurred. Swap the old and new live out - // sets to avoid copying. - BitSet temp = blockSets.liveOut; - blockSets.liveOut = liveOut; - liveOut = temp; - - changeOccurred = true; - changeOccurredInBlock = true; - } - } - - if (iterationCount == 0 || changeOccurredInBlock) { - // liveIn(block) is the union of liveGen(block) with (liveOut(block) & - // !liveKill(block)) - // note: liveIn has to be computed only in first iteration - // or if liveOut has changed! - BitSet liveIn = blockSets.liveIn; - liveIn.clear(); - liveIn.or(blockSets.liveOut); - liveIn.andNot(blockSets.liveKill); - liveIn.or(blockSets.liveGen); - - if (Debug.isLogEnabled()) { - Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); - } - } - } - iterationCount++; - - if (changeOccurred && iterationCount > 50) { - throw new BailoutException("too many iterations in computeGlobalLiveSets"); - } - } - } while (changeOccurred); - - if (DetailedAsserts.getValue()) { - verifyLiveness(); - } - - // check that the liveIn set of the first block is empty - AbstractBlockBase startBlock = ir.getControlFlowGraph().getStartBlock(); - if (blockData.get(startBlock).liveIn.cardinality() != 0) { - if (DetailedAsserts.getValue()) { - reportFailure(numBlocks); - } - // bailout if this occurs in product mode. - throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn); - } - } - } - - private void reportFailure(int numBlocks) { - try (Scope s = Debug.forceLog()) { - try (Indent indent = Debug.logAndIndent("report failure")) { - - BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; - try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { - for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Interval interval = intervalFor(operandNum); - if (interval != null) { - Value operand = interval.operand; - Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand)); - } else { - Debug.log("var %d; missing operand", operandNum); - } - } - } - - // print some additional information to simplify debugging - for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Interval interval = intervalFor(operandNum); - Value operand = null; - Object valueForOperandFromDebugContext = null; - if (interval != null) { - operand = interval.operand; - valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand); - } - try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) { - - Deque> definedIn = new ArrayDeque<>(); - HashSet> usedIn = new HashSet<>(); - for (AbstractBlockBase block : sortedBlocks) { - if (blockData.get(block).liveGen.get(operandNum)) { - usedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { - for (LIRInstruction ins : ir.getLIRforBlock(block)) { - try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { - ins.forEachState((liveStateOperand, mode, flags) -> { - Debug.log("operand=%s", liveStateOperand); - return liveStateOperand; - }); - } - } - } - } - if (blockData.get(block).liveKill.get(operandNum)) { - definedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { - for (LIRInstruction ins : ir.getLIRforBlock(block)) { - Debug.log("%d: %s", ins.id(), ins); - } - } - } - } - - int[] hitCount = new int[numBlocks]; - - while (!definedIn.isEmpty()) { - AbstractBlockBase block = definedIn.removeFirst(); - usedIn.remove(block); - for (AbstractBlockBase successor : block.getSuccessors()) { - if (successor.isLoopHeader()) { - if (!block.isLoopEnd()) { - definedIn.add(successor); - } - } else { - if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { - definedIn.add(successor); - } - } - } - } - try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { - for (AbstractBlockBase block : usedIn) { - Debug.log("B%d", block.getId()); - } - } - } - } - } - } catch (Throwable e) { - throw Debug.handle(e); - } - } - - private void verifyLiveness() { - // check that fixed intervals are not live at block boundaries - // (live set must be empty at fixed intervals) - for (AbstractBlockBase block : sortedBlocks) { - for (int j = 0; j <= maxRegisterNumber(); j++) { - assert !blockData.get(block).liveIn.get(j) : "liveIn set of fixed register must be empty"; - assert !blockData.get(block).liveOut.get(j) : "liveOut set of fixed register must be empty"; - assert !blockData.get(block).liveGen.get(j) : "liveGen set of fixed register must be empty"; - } - } - } - - void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { - if (!isProcessed(operand)) { - return; - } - - Interval interval = getOrCreateInterval(operand); - if (!kind.equals(LIRKind.Illegal)) { - interval.setKind(kind); - } - - interval.addRange(from, to); - - // Register use position at even instruction id. - interval.addUsePos(to & ~1, registerPriority); - - if (Debug.isLogEnabled()) { - Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name()); - } - } - - void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { - if (!isProcessed(operand)) { - return; - } - - Interval interval = getOrCreateInterval(operand); - if (!kind.equals(LIRKind.Illegal)) { - interval.setKind(kind); - } - - interval.addRange(tempPos, tempPos + 1); - interval.addUsePos(tempPos, registerPriority); - interval.addMaterializationValue(null); - - if (Debug.isLogEnabled()) { - Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name()); - } - } - boolean isProcessed(Value operand) { return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable(); } - void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { - if (!isProcessed(operand)) { - return; - } - int defPos = op.id(); - - Interval interval = getOrCreateInterval(operand); - if (!kind.equals(LIRKind.Illegal)) { - interval.setKind(kind); - } - - Range r = interval.first(); - if (r.from <= defPos) { - // Update the starting point (when a range is first created for a use, its - // start is the beginning of the current block until a def is encountered.) - r.from = defPos; - interval.addUsePos(defPos, registerPriority); - - } else { - // Dead value - make vacuous interval - // also add register priority for dead intervals - interval.addRange(defPos, defPos + 1); - interval.addUsePos(defPos, registerPriority); - if (Debug.isLogEnabled()) { - Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos); - } - } - - changeSpillDefinitionPos(interval, defPos); - if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { - // detection of method-parameters and roundfp-results - interval.setSpillState(SpillState.StartInMemory); - } - interval.addMaterializationValue(LinearScan.getMaterializedValue(op, operand, interval)); - - if (Debug.isLogEnabled()) { - Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); - } - } - - /** - * Determines the register priority for an instruction's output/result operand. - */ - static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { - if (op instanceof MoveOp) { - MoveOp move = (MoveOp) op; - if (optimizeMethodArgument(move.getInput())) { - return RegisterPriority.None; - } - } else if (op instanceof LabelOp) { - LabelOp label = (LabelOp) op; - if (label.isPhiIn()) { - return RegisterPriority.None; - } - } - - // all other operands require a register - return RegisterPriority.MustHaveRegister; - } - - /** - * Determines the priority which with an instruction's input operand will be allocated a - * register. - */ - static RegisterPriority registerPriorityOfInputOperand(EnumSet flags) { - if (flags.contains(OperandFlag.STACK)) { - return RegisterPriority.ShouldHaveRegister; - } - // all other operands require a register - return RegisterPriority.MustHaveRegister; - } - - private static boolean optimizeMethodArgument(Value value) { - /* - * Object method arguments that are passed on the stack are currently not optimized because - * this requires that the runtime visits method arguments during stack walking. - */ - return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object; - } - - /** - * Optimizes moves related to incoming stack based arguments. The interval for the destination - * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot. - */ - void handleMethodArguments(LIRInstruction op) { - if (op instanceof MoveOp) { - MoveOp move = (MoveOp) op; - if (optimizeMethodArgument(move.getInput())) { - StackSlot slot = asStackSlot(move.getInput()); - if (DetailedAsserts.getValue()) { - assert op.id() > 0 : "invalid id"; - assert blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; - assert isVariable(move.getResult()) : "result of move must be a variable"; - - if (Debug.isLogEnabled()) { - Debug.log("found move from stack slot %s to %s", slot, move.getResult()); - } - } - - Interval interval = intervalFor(move.getResult()); - interval.setSpillSlot(slot); - interval.assignLocation(slot); - } - } - } - - void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags, final boolean hintAtDef) { - if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) { - - op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> { - if (isVariableOrRegister(registerHint)) { - Interval from = getOrCreateInterval((AllocatableValue) registerHint); - Interval to = getOrCreateInterval((AllocatableValue) targetValue); - - /* hints always point from def to use */ - if (hintAtDef) { - to.setLocationHint(from); - } else { - from.setLocationHint(to); - } - if (Debug.isLogEnabled()) { - Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); - } - - return registerHint; - } - return null; - }); - } - } - - void buildIntervals() { - - try (Indent indent = Debug.logAndIndent("build intervals")) { - InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind()); - addRegisterHint(op, operand, mode, flags, true); - } - }; - - InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind()); - addRegisterHint(op, operand, mode, flags, false); - } - }; - - InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - RegisterPriority p = registerPriorityOfInputOperand(flags); - int opId = op.id(); - int blockFrom = getFirstLirInstructionId((blockForId(opId))); - addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind()); - addRegisterHint(op, operand, mode, flags, false); - } - }; - - InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - int opId = op.id(); - int blockFrom = getFirstLirInstructionId((blockForId(opId))); - RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind()); - addRegisterHint(op, operand, mode, flags, false); - } - }; - - InstructionValueConsumer stateProc = (op, operand, mode, flags) -> { - if (isVariableOrRegister(operand)) { - int opId = op.id(); - int blockFrom = getFirstLirInstructionId((blockForId(opId))); - addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind()); - } - }; - - // create a list with all caller-save registers (cpu, fpu, xmm) - Register[] callerSaveRegs = regAllocConfig.getRegisterConfig().getCallerSaveRegisters(); - - // iterate all blocks in reverse order - for (int i = blockCount() - 1; i >= 0; i--) { - - AbstractBlockBase block = blockAt(i); - try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { - - List instructions = ir.getLIRforBlock(block); - final int blockFrom = getFirstLirInstructionId(block); - int blockTo = getLastLirInstructionId(block); - - assert blockFrom == instructions.get(0).id(); - assert blockTo == instructions.get(instructions.size() - 1).id(); - - // Update intervals for operands live at the end of this block; - 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"; - AllocatableValue operand = intervalFor(operandNum).operand; - if (Debug.isLogEnabled()) { - Debug.log("live in %d: %s", operandNum, operand); - } - - addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal); - - // add special use positions for loop-end blocks when the - // interval is used anywhere inside this loop. It's possible - // that the block was part of a non-natural loop, so it might - // have an invalid loop index. - if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) { - intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); - } - } - - // iterate all instructions of the block in reverse order. - // definitions of intervals are processed before uses - for (int j = instructions.size() - 1; j >= 0; j--) { - final LIRInstruction op = instructions.get(j); - final int opId = op.id(); - - try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { - - // add a temp range for each register if operation destroys - // caller-save registers - if (op.destroysCallerSavedRegisters()) { - for (Register r : callerSaveRegs) { - if (attributes(r).isAllocatable()) { - addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal); - } - } - if (Debug.isLogEnabled()) { - Debug.log("operation destroys all caller-save registers"); - } - } - - op.visitEachOutput(outputConsumer); - op.visitEachTemp(tempConsumer); - op.visitEachAlive(aliveConsumer); - op.visitEachInput(inputConsumer); - - // Add uses of live locals from interpreter's point of view for proper - // debug information generation - // Treat these operands as temp values (if the live range is extended - // to a call site, the value would be in a register at - // the call otherwise) - op.visitEachState(stateProc); - - // special steps for some instructions (especially moves) - handleMethodArguments(op); - - } - - } // end of instruction iteration - } - } // end of block iteration - - // add the range [0, 1] to all fixed intervals. - // the register allocator need not handle unhandled fixed intervals - for (Interval interval : intervals) { - if (interval != null && isRegister(interval.operand)) { - interval.addRange(0, 1); - } - } - } - } - // * Phase 5: actual register allocation private static boolean isSorted(Interval[] intervals) { @@ -1461,30 +582,6 @@ sortedIntervals = combinedList; } - void allocateRegisters() { - try (Indent indent = Debug.logAndIndent("allocate registers")) { - Interval precoloredIntervals; - Interval notPrecoloredIntervals; - - Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); - precoloredIntervals = result.first; - notPrecoloredIntervals = result.second; - - // allocate cpu registers - LinearScanWalker lsw; - if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) { - lsw = new OptimizingLinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); - } else { - lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); - } - lsw.walk(); - lsw.finishAllocation(); - } - } - - // * Phase 6: resolve data flow - // (insert moves at edges between blocks if intervals have been split) - // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode // instead of returning null Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) { @@ -1500,405 +597,59 @@ throw new BailoutException("LinearScan: interval is null"); } - void resolveCollectMappings(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, AbstractBlockBase midBlock, MoveResolver moveResolver) { - assert moveResolver.checkEmpty(); - assert midBlock == null || - (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals( - toBlock)); - - int toBlockFirstInstructionId = getFirstLirInstructionId(toBlock); - int fromBlockLastInstructionId = getLastLirInstructionId(fromBlock) + 1; - int numOperands = operandSize(); - BitSet liveAtEdge = blockData.get(toBlock).liveIn; - - // visit all variables for which the liveAtEdge bit is set - for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { - assert operandNum < numOperands : "live information set for not exisiting interval"; - assert blockData.get(fromBlock).liveOut.get(operandNum) && blockData.get(toBlock).liveIn.get(operandNum) : "interval not live at this edge"; - - Interval fromInterval = splitChildAtOpId(intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF); - Interval toInterval = splitChildAtOpId(intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); - - if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { - // need to insert move instruction - moveResolver.addMapping(fromInterval, toInterval); - } - } - } - - void resolveFindInsertPos(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, MoveResolver moveResolver) { - if (fromBlock.getSuccessorCount() <= 1) { - if (Debug.isLogEnabled()) { - Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId()); - } - - List instructions = ir.getLIRforBlock(fromBlock); - LIRInstruction instr = instructions.get(instructions.size() - 1); - if (instr instanceof StandardOp.JumpOp) { - // insert moves before branch - moveResolver.setInsertPosition(instructions, instructions.size() - 1); - } else { - moveResolver.setInsertPosition(instructions, instructions.size()); - } - - } else { - if (Debug.isLogEnabled()) { - Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId()); - } - - if (DetailedAsserts.getValue()) { - assert ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; - - // because the number of predecessor edges matches the number of - // successor edges, blocks which are reached by switch statements - // may have be more than one predecessor but it will be guaranteed - // that all predecessors will be the same. - for (AbstractBlockBase predecessor : toBlock.getPredecessors()) { - assert fromBlock == predecessor : "all critical edges must be broken"; - } - } - - moveResolver.setInsertPosition(ir.getLIRforBlock(toBlock), 1); - } - } - - /** - * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that - * have been split. - */ - void resolveDataFlow() { - try (Indent indent = Debug.logAndIndent("resolve data flow")) { - - int numBlocks = blockCount(); - MoveResolver moveResolver = createMoveResolver(); - BitSet blockCompleted = new BitSet(numBlocks); - BitSet alreadyResolved = new BitSet(numBlocks); - - for (AbstractBlockBase block : sortedBlocks) { - - // check if block has only one predecessor and only one successor - if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { - List instructions = ir.getLIRforBlock(block); - assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; - assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; - - // check if block is empty (only label and branch) - if (instructions.size() == 2) { - AbstractBlockBase pred = block.getPredecessors().iterator().next(); - AbstractBlockBase sux = block.getSuccessors().iterator().next(); - - // prevent optimization of two consecutive blocks - if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { - if (Debug.isLogEnabled()) { - Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); - } - - blockCompleted.set(block.getLinearScanNumber()); - - // directly resolve between pred and sux (without looking - // at the empty block - // between) - resolveCollectMappings(pred, sux, block, moveResolver); - if (moveResolver.hasMappings()) { - moveResolver.setInsertPosition(instructions, 1); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - - for (AbstractBlockBase fromBlock : sortedBlocks) { - if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { - alreadyResolved.clear(); - alreadyResolved.or(blockCompleted); - - for (AbstractBlockBase toBlock : fromBlock.getSuccessors()) { - - // check for duplicate edges between the same blocks (can happen with switch - // blocks) - if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { - if (Debug.isLogEnabled()) { - Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); - } - - alreadyResolved.set(toBlock.getLinearScanNumber()); - - // collect all intervals that have been split between - // fromBlock and toBlock - resolveCollectMappings(fromBlock, toBlock, null, moveResolver); - if (moveResolver.hasMappings()) { - resolveFindInsertPos(fromBlock, toBlock, moveResolver); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - - } - } - - // * Phase 7: assign register numbers back to LIR - // (includes computation of debug information and oop maps) - static StackSlotValue canonicalSpillOpr(Interval interval) { assert interval.spillSlot() != null : "canonical spill slot not set"; return interval.spillSlot(); } - /** - * Assigns the allocated location for an LIR instruction operand back into the instruction. - * - * @param operand an LIR instruction operand - * @param opId the id of the LIR instruction using {@code operand} - * @param mode the usage mode for {@code operand} by the instruction - * @return the location assigned for the operand - */ - private Value colorLirOperand(Variable operand, int opId, OperandMode mode) { + boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) { Interval interval = intervalFor(operand); assert interval != null : "interval must exist"; if (opId != -1) { - if (DetailedAsserts.getValue()) { - AbstractBlockBase block = blockForId(opId); - if (block.getSuccessorCount() <= 1 && opId == getLastLirInstructionId(block)) { - /* - * Check if spill moves could have been appended at the end of this block, but - * before the branch instruction. So the split child information for this branch - * would be incorrect. - */ - LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1); - if (instr instanceof StandardOp.JumpOp) { - if (blockData.get(block).liveOut.get(operandNumber(operand))) { - assert false : String.format( - "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s", - block, instr, operand); - } - } - } - } - - // operands are not changed when an interval is split during allocation, - // so search the right interval here - interval = splitChildAtOpId(interval, opId, mode); - } - - if (isIllegal(interval.location()) && interval.canMaterialize()) { - assert mode != OperandMode.DEF; - return interval.getMaterializedValue(); - } - return interval.location(); - } - - private boolean isMaterialized(AllocatableValue operand, int opId, OperandMode mode) { - Interval interval = intervalFor(operand); - assert interval != null : "interval must exist"; - - if (opId != -1) { - // operands are not changed when an interval is split during allocation, - // so search the right interval here + /* + * Operands are not changed when an interval is split during allocation, so search the + * right interval here. + */ interval = splitChildAtOpId(interval, opId, mode); } return isIllegal(interval.location()) && interval.canMaterialize(); } - protected IntervalWalker initIntervalWalker(IntervalPredicate predicate) { - // setup lists of potential oops for walking - Interval oopIntervals; - Interval nonOopIntervals; - - oopIntervals = createUnhandledLists(predicate, null).first; - - // intervals that have no oops inside need not to be processed. - // to ensure a walking until the last instruction id, add a dummy interval - // with a high operation id - nonOopIntervals = new Interval(Value.ILLEGAL, -1); - nonOopIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1); - - return new IntervalWalker(this, oopIntervals, nonOopIntervals); - } - - private boolean isCallerSave(Value operand) { + boolean isCallerSave(Value operand) { return attributes(asRegister(operand)).isCallerSave(); } - /** - * @param op - * @param operand - * @param valueMode - * @param flags - * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet) - */ - private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet flags) { - if (isVirtualStackSlot(operand)) { - return operand; - } - int tempOpId = op.id(); - OperandMode mode = OperandMode.USE; - AbstractBlockBase block = blockForId(tempOpId); - if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) { - // generating debug information for the last instruction of a block. - // if this instruction is a branch, spill moves are inserted before this branch - // and so the wrong operand would be returned (spill moves at block boundaries - // are not - // considered in the live ranges of intervals) - // Solution: use the first opId of the branch target block instead. - final LIRInstruction instr = ir.getLIRforBlock(block).get(ir.getLIRforBlock(block).size() - 1); - if (instr instanceof StandardOp.JumpOp) { - if (blockData.get(block).liveOut.get(operandNumber(operand))) { - tempOpId = getFirstLirInstructionId(block.getSuccessors().iterator().next()); - mode = OperandMode.DEF; - } - } - } - - // Get current location of operand - // The operand must be live because debug information is considered when building - // the intervals - // if the interval is not live, colorLirOperand will cause an assert on failure - Value result = colorLirOperand((Variable) operand, tempOpId, mode); - assert !hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls"; - return result; - } - - private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) { - info.forEachState(op, this::debugInfoProcedure); - } - - private void assignLocations(List instructions) { - int numInst = instructions.size(); - boolean hasDead = false; - - InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand; - for (int j = 0; j < numInst; j++) { - final LIRInstruction op = instructions.get(j); - if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves - hasDead = true; - continue; - } - - // remove useless moves - MoveOp move = null; - if (op instanceof MoveOp) { - move = (MoveOp) op; - AllocatableValue result = move.getResult(); - if (isVariable(result) && isMaterialized(result, op.id(), OperandMode.DEF)) { - /* - * This happens if a materializable interval is originally not spilled but then - * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an - * interval this move operation was already generated. - */ - instructions.set(j, null); - hasDead = true; - continue; - } - } - - op.forEachInput(assignProc); - op.forEachAlive(assignProc); - op.forEachTemp(assignProc); - op.forEachOutput(assignProc); - - // compute reference map and debug information - op.forEachState((inst, state) -> computeDebugInfo(inst, state)); - - // remove useless moves - if (move != null) { - if (move.getInput().equals(move.getResult())) { - instructions.set(j, null); - hasDead = true; - } - } - } - - if (hasDead) { - // Remove null values from the list. - instructions.removeAll(Collections.singleton(null)); - } - } - - private void assignLocations() { - try (Indent indent = Debug.logAndIndent("assign locations")) { - for (AbstractBlockBase block : sortedBlocks) { - try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { - assignLocations(ir.getLIRforBlock(block)); - } - } - } - } - - private static final DebugTimer lifetimeTimer = Debug.timer("LinearScan_LifetimeAnalysis"); - private static final DebugTimer registerAllocationTimer = Debug.timer("LinearScan_RegisterAllocation"); - private static final DebugTimer optimizedSpillPositionTimer = Debug.timer("LinearScan_OptimizeSpillPosition"); - private static final DebugTimer resolveDataFlowTimer = Debug.timer("LinearScan_ResolveDataFlow"); - private static final DebugTimer eliminateSpillMoveTimer = Debug.timer("LinearScan_EliminateSpillMove"); - private static final DebugTimer assignLocationsTimer = Debug.timer("LinearScan_AssignLocations"); - - void allocate() { + > void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { /* * This is the point to enable debug logging for the whole register allocation. */ try (Indent indent = Debug.logAndIndent("LinearScan allocate")) { + AllocationContext context = new AllocationContext(spillMoveFactory, registerAllocationConfig); - try (Scope s = Debug.scope("LifetimeAnalysis"); DebugCloseable a = lifetimeTimer.start()) { - numberInstructions(); - printLir("Before register allocation", true); - computeLocalLiveSets(); - computeGlobalLiveSets(); - buildIntervals(); + createLifetimeAnalysisPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + + try (Scope s = Debug.scope("AfterLifetimeAnalysis", intervals)) { sortIntervalsBeforeAllocation(); - } catch (Throwable e) { - throw Debug.handle(e); - } - try (Scope s = Debug.scope("RegisterAllocation"); DebugCloseable a = registerAllocationTimer.start()) { - printIntervals("Before register allocation"); - allocateRegisters(); - } catch (Throwable e) { - throw Debug.handle(e); - } + createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); - if (Options.LSRAOptimizeSpillPosition.getValue()) { - try (Scope s = Debug.scope("OptimizeSpillPosition"); DebugCloseable a = optimizedSpillPositionTimer.start()) { - optimizeSpillPosition(); - } catch (Throwable e) { - throw Debug.handle(e); + if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); } - } - - try (Scope s = Debug.scope("ResolveDataFlow"); DebugCloseable a = resolveDataFlowTimer.start()) { - resolveDataFlow(); - } catch (Throwable e) { - throw Debug.handle(e); - } - - try (Scope s = Debug.scope("DebugInfo")) { - printIntervals("After register allocation"); - printLir("After register allocation", true); + createResolveDataFlowPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context); sortIntervalsAfterAllocation(); if (DetailedAsserts.getValue()) { verify(); } - beforeSpillMoveElimination(); - - try (Scope s1 = Debug.scope("EliminateSpillMove"); DebugCloseable a = eliminateSpillMoveTimer.start()) { - eliminateSpillMoves(); - } catch (Throwable e) { - throw Debug.handle(e); - } - printLir("After spill move elimination", true); - - try (Scope s1 = Debug.scope("AssignLocations"); DebugCloseable a = assignLocationsTimer.start()) { - assignLocations(); - } catch (Throwable e) { - throw Debug.handle(e); - } + createSpillMoveEliminationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context); + createAssignLocationsPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context); if (DetailedAsserts.getValue()) { verifyIntervals(); @@ -1906,173 +657,34 @@ } catch (Throwable e) { throw Debug.handle(e); } - - printLir("After register number assignment", true); } } protected void beforeSpillMoveElimination() { } - private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition"); - private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability"); - - private void optimizeSpillPosition() { - LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[ir.linearScanOrder().size()]; - for (Interval interval : intervals) { - if (interval != null && interval.isSplitParent() && interval.spillState() == SpillState.SpillInDominator) { - AbstractBlockBase defBlock = blockForId(interval.spillDefinitionPos()); - AbstractBlockBase spillBlock = null; - Interval firstSpillChild = null; - try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) { - for (Interval splitChild : interval.getSplitChildren()) { - if (isStackSlotValue(splitChild.location())) { - if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) { - firstSpillChild = splitChild; - } else { - assert firstSpillChild.from() < splitChild.from(); - } - // iterate all blocks where the interval has use positions - for (AbstractBlockBase splitBlock : blocksForInterval(splitChild)) { - if (dominates(defBlock, splitBlock)) { - if (Debug.isLogEnabled()) { - Debug.log("Split interval %s, block %s", splitChild, splitBlock); - } - if (spillBlock == null) { - spillBlock = splitBlock; - } else { - spillBlock = commonDominator(spillBlock, splitBlock); - assert spillBlock != null; - } - } - } - } - } - if (spillBlock == null) { - // no spill interval - interval.setSpillState(SpillState.StoreAtDefinition); - } else { - // move out of loops - if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) { - spillBlock = moveSpillOutOfLoop(defBlock, spillBlock); - } + protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { + return new LinearScanLifetimeAnalysisPhase(this); + } - /* - * If the spill block is the begin of the first split child (aka the value - * is on the stack) spill in the dominator. - */ - assert firstSpillChild != null; - if (!defBlock.equals(spillBlock) && spillBlock.equals(blockForId(firstSpillChild.from()))) { - AbstractBlockBase dom = spillBlock.getDominator(); - if (Debug.isLogEnabled()) { - Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom); - } - spillBlock = dom; - } - - if (!defBlock.equals(spillBlock)) { - assert dominates(defBlock, spillBlock); - betterSpillPos.increment(); - if (Debug.isLogEnabled()) { - Debug.log("Better spill position found (Block %s)", spillBlock); - } - - if (defBlock.probability() <= spillBlock.probability()) { - // better spill block has the same probability -> do nothing - interval.setSpillState(SpillState.StoreAtDefinition); - } else { - LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()]; - if (insertionBuffer == null) { - insertionBuffer = new LIRInsertionBuffer(); - insertionBuffers[spillBlock.getId()] = insertionBuffer; - insertionBuffer.init(ir.getLIRforBlock(spillBlock)); - } - int spillOpId = getFirstLirInstructionId(spillBlock); - // insert spill move - AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, this).location(); - AllocatableValue toLocation = canonicalSpillOpr(interval); - LIRInstruction move = getSpillMoveFactory().createMove(toLocation, fromLocation); - move.setId(DOMINATOR_SPILL_MOVE_ID); - /* - * We can use the insertion buffer directly because we always insert - * at position 1. - */ - insertionBuffer.append(1, move); - - betterSpillPosWithLowerProbability.increment(); - interval.setSpillDefinitionPos(spillOpId); - } - } else { - // definition is the best choice - interval.setSpillState(SpillState.StoreAtDefinition); - } - } - } - } - } - for (LIRInsertionBuffer insertionBuffer : insertionBuffers) { - if (insertionBuffer != null) { - assert insertionBuffer.initialized() : "Insertion buffer is nonnull but not initialized!"; - insertionBuffer.finish(); - } - } + protected LinearScanRegisterAllocationPhase createRegisterAllocationPhase() { + return new LinearScanRegisterAllocationPhase(this); } - /** - * Iterate over all {@link AbstractBlockBase blocks} of an interval. - */ - private class IntervalBlockIterator implements Iterator> { - - Range range; - AbstractBlockBase block; - - public IntervalBlockIterator(Interval interval) { - range = interval.first(); - block = blockForId(range.from); - } - - public AbstractBlockBase next() { - AbstractBlockBase currentBlock = block; - int nextBlockIndex = block.getLinearScanNumber() + 1; - if (nextBlockIndex < sortedBlocks.size()) { - block = sortedBlocks.get(nextBlockIndex); - if (range.to <= getFirstLirInstructionId(block)) { - range = range.next; - if (range == Range.EndMarker) { - block = null; - } else { - block = blockForId(range.from); - } - } - } else { - block = null; - } - return currentBlock; - } - - public boolean hasNext() { - return block != null; - } + protected LinearScanOptimizeSpillPositionPhase createOptimizeSpillPositionPhase() { + return new LinearScanOptimizeSpillPositionPhase(this); } - private Iterable> blocksForInterval(Interval interval) { - return new Iterable>() { - public Iterator> iterator() { - return new IntervalBlockIterator(interval); - } - }; + protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { + return new LinearScanResolveDataFlowPhase(this); } - private static AbstractBlockBase moveSpillOutOfLoop(AbstractBlockBase defBlock, AbstractBlockBase spillBlock) { - int defLoopDepth = defBlock.getLoopDepth(); - for (AbstractBlockBase block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) { - assert block != null : "spill block not dominated by definition block?"; - if (block.getLoopDepth() <= defLoopDepth) { - assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!"; - return block; - } - } - return defBlock; + protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { + return new LinearScanEliminateSpillMovePhase(this); + } + + protected LinearScanAssignLocationsPhase createAssignLocationsPhase() { + return new LinearScanAssignLocationsPhase(this); } void printIntervals(String label) { @@ -2229,14 +841,18 @@ iw.walkBefore(op.id()); boolean checkLive = true; - // Make sure none of the fixed registers is live across an - // oopmap since we can't handle that correctly. + /* + * Make sure none of the fixed registers is live across an oopmap since we + * can't handle that correctly. + */ if (checkLive) { for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { if (interval.currentTo() > op.id() + 1) { - // This interval is live out of this op so make sure - // that this interval represents some value that's - // referenced by this op either as an input or output. + /* + * This interval is live out of this op so make sure that this + * interval represents some value that's referenced by this op + * either as an input or output. + */ checkConsumer.curInterval = interval; checkConsumer.ok = false; @@ -2255,37 +871,4 @@ } } - /** - * Returns a value for a interval definition, which can be used for re-materialization. - * - * @param op An instruction which defines a value - * @param operand The destination operand of the instruction - * @param interval The interval for this defined value. - * @return Returns the value which is moved to the instruction and which can be reused at all - * reload-locations in case the interval of this instruction is spilled. Currently this - * can only be a {@link JavaConstant}. - */ - public static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { - if (op instanceof MoveOp) { - MoveOp move = (MoveOp) op; - if (move.getInput() instanceof JavaConstant) { - /* - * Check if the interval has any uses which would accept an stack location (priority - * == ShouldHaveRegister). Rematerialization of such intervals can result in a - * degradation, because rematerialization always inserts a constant load, even if - * the value is not needed in a register. - */ - Interval.UsePosList usePosList = interval.usePosList(); - int numUsePos = usePosList.size(); - for (int useIdx = 0; useIdx < numUsePos; useIdx++) { - Interval.RegisterPriority priority = usePosList.registerPriority(useIdx); - if (priority == Interval.RegisterPriority.ShouldHaveRegister) { - return null; - } - } - return (JavaConstant) move.getInput(); - } - } - return null; - } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.lir.LIRValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.*; +import com.oracle.graal.lir.phases.*; + +/** + * Phase 7: Assign register numbers back to LIR. + */ +final class LinearScanAssignLocationsPhase extends AllocationPhase { + + private final LinearScan allocator; + + LinearScanAssignLocationsPhase(LinearScan allocator) { + this.allocator = allocator; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + assignLocations(); + } + + /** + * Assigns the allocated location for an LIR instruction operand back into the instruction. + * + * @param operand an LIR instruction operand + * @param opId the id of the LIR instruction using {@code operand} + * @param mode the usage mode for {@code operand} by the instruction + * @return the location assigned for the operand + */ + private Value colorLirOperand(Variable operand, int opId, OperandMode mode) { + Interval interval = allocator.intervalFor(operand); + assert interval != null : "interval must exist"; + + if (opId != -1) { + if (DetailedAsserts.getValue()) { + AbstractBlockBase block = allocator.blockForId(opId); + if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) { + /* + * Check if spill moves could have been appended at the end of this block, but + * before the branch instruction. So the split child information for this branch + * would be incorrect. + */ + LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1); + if (instr instanceof StandardOp.JumpOp) { + if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { + assert false : String.format( + "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s", + block, instr, operand); + } + } + } + } + + /* + * Operands are not changed when an interval is split during allocation, so search the + * right interval here. + */ + interval = allocator.splitChildAtOpId(interval, opId, mode); + } + + if (isIllegal(interval.location()) && interval.canMaterialize()) { + assert mode != OperandMode.DEF; + return interval.getMaterializedValue(); + } + return interval.location(); + } + + /** + * @param op + * @param operand + * @param valueMode + * @param flags + * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet) + */ + private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + return operand; + } + int tempOpId = op.id(); + OperandMode mode = OperandMode.USE; + AbstractBlockBase block = allocator.blockForId(tempOpId); + if (block.getSuccessorCount() == 1 && tempOpId == allocator.getLastLirInstructionId(block)) { + /* + * Generating debug information for the last instruction of a block. If this instruction + * is a branch, spill moves are inserted before this branch and so the wrong operand + * would be returned (spill moves at block boundaries are not considered in the live + * ranges of intervals). + * + * Solution: use the first opId of the branch target block instead. + */ + final LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1); + if (instr instanceof StandardOp.JumpOp) { + if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { + tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next()); + mode = OperandMode.DEF; + } + } + } + + /* + * Get current location of operand. The operand must be live because debug information is + * considered when building the intervals if the interval is not live, colorLirOperand will + * cause an assert on failure. + */ + Value result = colorLirOperand((Variable) operand, tempOpId, mode); + assert !allocator.hasCall(tempOpId) || isStackSlotValue(result) || isConstant(result) || !allocator.isCallerSave(result) : "cannot have caller-save register operands at calls"; + return result; + } + + private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) { + info.forEachState(op, this::debugInfoProcedure); + } + + private void assignLocations(List instructions) { + int numInst = instructions.size(); + boolean hasDead = false; + + InstructionValueProcedure assignProc = (op, operand, mode, flags) -> isVariable(operand) ? colorLirOperand((Variable) operand, op.id(), mode) : operand; + for (int j = 0; j < numInst; j++) { + final LIRInstruction op = instructions.get(j); + if (op == null) { + /* + * this can happen when spill-moves are removed in eliminateSpillMoves + */ + hasDead = true; + continue; + } + + // remove useless moves + MoveOp move = null; + if (op instanceof MoveOp) { + move = (MoveOp) op; + AllocatableValue result = move.getResult(); + if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) { + /* + * This happens if a materializable interval is originally not spilled but then + * kicked out in LinearScanWalker.splitForSpilling(). When kicking out such an + * interval this move operation was already generated. + */ + instructions.set(j, null); + hasDead = true; + continue; + } + } + + op.forEachInput(assignProc); + op.forEachAlive(assignProc); + op.forEachTemp(assignProc); + op.forEachOutput(assignProc); + + // compute reference map and debug information + op.forEachState((inst, state) -> computeDebugInfo(inst, state)); + + // remove useless moves + if (move != null) { + if (move.getInput().equals(move.getResult())) { + instructions.set(j, null); + hasDead = true; + } + } + } + + if (hasDead) { + // Remove null values from the list. + instructions.removeAll(Collections.singleton(null)); + } + } + + private void assignLocations() { + try (Indent indent = Debug.logAndIndent("assign locations")) { + for (AbstractBlockBase block : allocator.sortedBlocks) { + try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { + assignLocations(allocator.ir.getLIRforBlock(block)); + } + } + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.lir.LIRValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.alloc.lsra.Interval.*; +import com.oracle.graal.lir.alloc.lsra.LinearScan.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.*; +import com.oracle.graal.lir.phases.*; + +class LinearScanEliminateSpillMovePhase extends AllocationPhase { + + private static final IntervalPredicate mustStoreAtDefinition = new LinearScan.IntervalPredicate() { + + @Override + public boolean apply(Interval i) { + return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition; + } + }; + + protected final LinearScan allocator; + + LinearScanEliminateSpillMovePhase(LinearScan allocator) { + this.allocator = allocator; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + eliminateSpillMoves(); + } + + /** + * @return the index of the first instruction that is of interest for + * {@link #eliminateSpillMoves()} + */ + protected int firstInstructionOfInterest() { + // skip the first because it is always a label + return 1; + } + + // called once before assignment of register numbers + void eliminateSpillMoves() { + try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) { + + /* + * collect all intervals that must be stored after their definition. The list is sorted + * by Interval.spillDefinitionPos. + */ + Interval interval; + interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).first; + if (DetailedAsserts.getValue()) { + checkIntervals(interval); + } + + LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); + for (AbstractBlockBase block : allocator.sortedBlocks) { + try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) { + List instructions = allocator.ir.getLIRforBlock(block); + int numInst = instructions.size(); + + // iterate all instructions of the block. + for (int j = firstInstructionOfInterest(); j < numInst; j++) { + LIRInstruction op = instructions.get(j); + int opId = op.id(); + + if (opId == -1) { + MoveOp move = (MoveOp) op; + /* + * Remove move from register to stack if the stack slot is guaranteed to + * be correct. Only moves that have been inserted by LinearScan can be + * removed. + */ + if (canEliminateSpillMove(block, move)) { + /* + * Move target is a stack slot that is always correct, so eliminate + * instruction. + */ + if (Debug.isLogEnabled()) { + Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(move.getInput()), move.getInput(), + allocator.operandNumber(move.getResult()), move.getResult(), block); + } + + // null-instructions are deleted by assignRegNum + instructions.set(j, null); + } + + } else { + /* + * Insert move from register to stack just after the beginning of the + * interval. + */ + assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; + assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; + + while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { + if (!interval.canMaterialize()) { + if (!insertionBuffer.initialized()) { + /* + * prepare insertion buffer (appended when all instructions + * in the block are processed) + */ + insertionBuffer.init(instructions); + } + + AllocatableValue fromLocation = interval.location(); + AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval); + if (!fromLocation.equals(toLocation)) { + + assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + + interval.spillState(); + assert isStackSlotValue(toLocation) : "to operand must be a stack slot"; + + LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation); + insertionBuffer.append(j + 1, move); + + if (Debug.isLogEnabled()) { + Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); + } + } + } + interval = interval.next; + } + } + } // end of instruction iteration + + if (insertionBuffer.initialized()) { + insertionBuffer.finish(); + } + } + } // end of block iteration + + assert interval == Interval.EndMarker : "missed an interval"; + } + } + + /** + * @param block The block {@code move} is located in. + * @param move Spill move. + */ + protected boolean canEliminateSpillMove(AbstractBlockBase block, MoveOp move) { + assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables: " + move; + + Interval curInterval = allocator.intervalFor(move.getResult()); + + if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { + assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); + return true; + } + return false; + } + + private static void checkIntervals(Interval interval) { + Interval prev = null; + Interval temp = interval; + while (temp != Interval.EndMarker) { + assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos"; + if (prev != null) { + assert temp.from() >= prev.from() : "intervals not sorted"; + assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from : then they must also be sorted by spillDefinitionPos"; + } + + assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned"; + assert temp.spillDefinitionPos() >= temp.from() : "invalid order"; + assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized"; + + if (Debug.isLogEnabled()) { + Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos()); + } + + prev = temp; + temp = temp.next; + } + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,830 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.lir.LIRValueUtil.*; +import static com.oracle.graal.lir.debug.LIRGenerationDebugContext.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.compiler.common.util.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; +import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; +import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; + +class LinearScanLifetimeAnalysisPhase extends AllocationPhase { + + protected final LinearScan allocator; + + /** + * @param linearScan + */ + LinearScanLifetimeAnalysisPhase(LinearScan linearScan) { + allocator = linearScan; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + numberInstructions(); + allocator.printLir("Before register allocation", true); + computeLocalLiveSets(); + computeGlobalLiveSets(); + buildIntervals(); + } + + /** + * Bit set for each variable that is contained in each loop. + */ + BitMap2D intervalInLoop; + + boolean isIntervalInLoop(int interval, int loop) { + return intervalInLoop.at(interval, loop); + } + + /** + * Numbers all instructions in all blocks. The numbering follows the + * {@linkplain ComputeBlockOrder linear scan order}. + */ + void numberInstructions() { + + allocator.initIntervals(); + + ValueConsumer setVariableConsumer = (value, mode, flags) -> { + if (isVariable(value)) { + allocator.getOrCreateInterval(asVariable(value)); + } + }; + + // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. + int numInstructions = 0; + for (AbstractBlockBase block : allocator.sortedBlocks) { + numInstructions += allocator.ir.getLIRforBlock(block).size(); + } + + // initialize with correct length + allocator.initOpIdMaps(numInstructions); + + int opId = 0; + int index = 0; + for (AbstractBlockBase block : allocator.sortedBlocks) { + allocator.initBlockData(block); + + List instructions = allocator.ir.getLIRforBlock(block); + + int numInst = instructions.size(); + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + op.setId(opId); + + allocator.putOpIdMaps(index, op, block); + assert allocator.instructionForId(opId) == op : "must match"; + + op.visitEachTemp(setVariableConsumer); + op.visitEachOutput(setVariableConsumer); + + index++; + opId += 2; // numbering of lirOps by two + } + } + assert index == numInstructions : "must match"; + assert (index << 1) == opId : "must match: " + (index << 1); + } + + /** + * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill}) + * separately for each block. + */ + void computeLocalLiveSets() { + int liveSize = allocator.liveSetSize(); + + intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops()); + + // iterate all blocks + for (final AbstractBlockBase block : allocator.sortedBlocks) { + try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) { + + final BitSet liveGen = new BitSet(liveSize); + final BitSet liveKill = new BitSet(liveSize); + + List instructions = allocator.ir.getLIRforBlock(block); + int numInst = instructions.size(); + + ValueConsumer useConsumer = (operand, mode, flags) -> { + if (isVariable(operand)) { + int operandNum = allocator.operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + if (Debug.isLogEnabled()) { + Debug.log("liveGen for operand %d(%s)", operandNum, operand); + } + } + if (block.getLoop() != null) { + intervalInLoop.setBit(operandNum, block.getLoop().getIndex()); + } + } + + if (DetailedAsserts.getValue()) { + verifyInput(block, liveKill, operand); + } + }; + ValueConsumer stateConsumer = (operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + int operandNum = allocator.operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + if (Debug.isLogEnabled()) { + Debug.log("liveGen in state for operand %d(%s)", operandNum, operand); + } + } + } + }; + ValueConsumer defConsumer = (operand, mode, flags) -> { + if (isVariable(operand)) { + int varNum = allocator.operandNumber(operand); + liveKill.set(varNum); + if (Debug.isLogEnabled()) { + Debug.log("liveKill for operand %d(%s)", varNum, operand); + } + if (block.getLoop() != null) { + intervalInLoop.setBit(varNum, block.getLoop().getIndex()); + } + } + + if (DetailedAsserts.getValue()) { + /* + * Fixed intervals are never live at block boundaries, so they need not be + * processed in live sets. Process them only in debug mode so that this can + * be checked + */ + verifyTemp(liveKill, operand); + } + }; + + // iterate all instructions of the block + for (int j = 0; j < numInst; j++) { + final LIRInstruction op = instructions.get(j); + + try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { + op.visitEachInput(useConsumer); + op.visitEachAlive(useConsumer); + /* + * Add uses of live locals from interpreter's point of view for proper debug + * information generation. + */ + op.visitEachState(stateConsumer); + op.visitEachTemp(defConsumer); + op.visitEachOutput(defConsumer); + } + } // end of instruction iteration + + BlockData blockSets = allocator.getBlockData(block); + blockSets.liveGen = liveGen; + blockSets.liveKill = liveKill; + blockSets.liveIn = new BitSet(liveSize); + blockSets.liveOut = new BitSet(liveSize); + + if (Debug.isLogEnabled()) { + Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); + Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); + } + + } + } // end of block iteration + } + + private void verifyTemp(BitSet liveKill, Value operand) { + /* + * Fixed intervals are never live at block boundaries, so they need not be processed in live + * sets. Process them only in debug mode so that this can be checked + */ + if (isRegister(operand)) { + if (allocator.isProcessed(operand)) { + liveKill.set(allocator.operandNumber(operand)); + } + } + } + + private void verifyInput(AbstractBlockBase block, BitSet liveKill, Value operand) { + /* + * Fixed intervals are never live at block boundaries, so they need not be processed in live + * sets. This is checked by these assertions to be sure about it. The entry block may have + * incoming values in registers, which is ok. + */ + if (isRegister(operand) && block != allocator.ir.getControlFlowGraph().getStartBlock()) { + if (allocator.isProcessed(operand)) { + assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block"; + } + } + } + + /** + * Performs a backward dataflow analysis to compute global live sets (i.e. + * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. + */ + void computeGlobalLiveSets() { + try (Indent indent = Debug.logAndIndent("compute global live sets")) { + int numBlocks = allocator.blockCount(); + boolean changeOccurred; + boolean changeOccurredInBlock; + int iterationCount = 0; + BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations + + /* + * Perform a backward dataflow analysis to compute liveOut and liveIn for each block. + * The loop is executed until a fixpoint is reached (no changes in an iteration). + */ + do { + changeOccurred = false; + + try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { + + // iterate all blocks in reverse order + for (int i = numBlocks - 1; i >= 0; i--) { + AbstractBlockBase block = allocator.blockAt(i); + BlockData blockSets = allocator.getBlockData(block); + + changeOccurredInBlock = false; + + /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */ + int n = block.getSuccessorCount(); + if (n > 0) { + liveOut.clear(); + // block has successors + if (n > 0) { + for (AbstractBlockBase successor : block.getSuccessors()) { + liveOut.or(allocator.getBlockData(successor).liveIn); + } + } + + if (!blockSets.liveOut.equals(liveOut)) { + /* + * A change occurred. Swap the old and new live out sets to avoid + * copying. + */ + BitSet temp = blockSets.liveOut; + blockSets.liveOut = liveOut; + liveOut = temp; + + changeOccurred = true; + changeOccurredInBlock = true; + } + } + + if (iterationCount == 0 || changeOccurredInBlock) { + /* + * liveIn(block) is the union of liveGen(block) with (liveOut(block) & + * !liveKill(block)). + * + * Note: liveIn has to be computed only in first iteration or if liveOut + * has changed! + */ + BitSet liveIn = blockSets.liveIn; + liveIn.clear(); + liveIn.or(blockSets.liveOut); + liveIn.andNot(blockSets.liveKill); + liveIn.or(blockSets.liveGen); + + if (Debug.isLogEnabled()) { + Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); + } + } + } + iterationCount++; + + if (changeOccurred && iterationCount > 50) { + throw new BailoutException("too many iterations in computeGlobalLiveSets"); + } + } + } while (changeOccurred); + + if (DetailedAsserts.getValue()) { + verifyLiveness(); + } + + // check that the liveIn set of the first block is empty + AbstractBlockBase startBlock = allocator.ir.getControlFlowGraph().getStartBlock(); + if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) { + if (DetailedAsserts.getValue()) { + reportFailure(numBlocks); + } + // bailout if this occurs in product mode. + throw new GraalInternalError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn); + } + } + } + + private void reportFailure(int numBlocks) { + try (Scope s = Debug.forceLog()) { + try (Indent indent = Debug.logAndIndent("report failure")) { + + BitSet startBlockLiveIn = allocator.getBlockData(allocator.ir.getControlFlowGraph().getStartBlock()).liveIn; + try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { + for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { + Interval interval = allocator.intervalFor(operandNum); + if (interval != null) { + Value operand = interval.operand; + Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(operand)); + } else { + Debug.log("var %d; missing operand", operandNum); + } + } + } + + // print some additional information to simplify debugging + for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { + Interval interval = allocator.intervalFor(operandNum); + Value operand = null; + Object valueForOperandFromDebugContext = null; + if (interval != null) { + operand = interval.operand; + valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(operand); + } + try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) { + + Deque> definedIn = new ArrayDeque<>(); + HashSet> usedIn = new HashSet<>(); + for (AbstractBlockBase block : allocator.sortedBlocks) { + if (allocator.getBlockData(block).liveGen.get(operandNum)) { + usedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { + for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) { + try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { + ins.forEachState((liveStateOperand, mode, flags) -> { + Debug.log("operand=%s", liveStateOperand); + return liveStateOperand; + }); + } + } + } + } + if (allocator.getBlockData(block).liveKill.get(operandNum)) { + definedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { + for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) { + Debug.log("%d: %s", ins.id(), ins); + } + } + } + } + + int[] hitCount = new int[numBlocks]; + + while (!definedIn.isEmpty()) { + AbstractBlockBase block = definedIn.removeFirst(); + usedIn.remove(block); + for (AbstractBlockBase successor : block.getSuccessors()) { + if (successor.isLoopHeader()) { + if (!block.isLoopEnd()) { + definedIn.add(successor); + } + } else { + if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { + definedIn.add(successor); + } + } + } + } + try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { + for (AbstractBlockBase block : usedIn) { + Debug.log("B%d", block.getId()); + } + } + } + } + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + private void verifyLiveness() { + /* + * Check that fixed intervals are not live at block boundaries (live set must be empty at + * fixed intervals). + */ + for (AbstractBlockBase block : allocator.sortedBlocks) { + for (int j = 0; j <= allocator.maxRegisterNumber(); j++) { + assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn set of fixed register must be empty"; + assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty"; + assert !allocator.getBlockData(block).liveGen.get(j) : "liveGen set of fixed register must be empty"; + } + } + } + + void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + interval.addRange(from, to); + + // Register use position at even instruction id. + interval.addUsePos(to & ~1, registerPriority); + + if (Debug.isLogEnabled()) { + Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name()); + } + } + + void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + interval.addRange(tempPos, tempPos + 1); + interval.addUsePos(tempPos, registerPriority); + interval.addMaterializationValue(null); + + if (Debug.isLogEnabled()) { + Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name()); + } + } + + void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + int defPos = op.id(); + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + Range r = interval.first(); + if (r.from <= defPos) { + /* + * Update the starting point (when a range is first created for a use, its start is the + * beginning of the current block until a def is encountered). + */ + r.from = defPos; + interval.addUsePos(defPos, registerPriority); + + } else { + /* + * Dead value - make vacuous interval also add register priority for dead intervals + */ + interval.addRange(defPos, defPos + 1); + interval.addUsePos(defPos, registerPriority); + if (Debug.isLogEnabled()) { + Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos); + } + } + + changeSpillDefinitionPos(interval, defPos); + if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { + // detection of method-parameters and roundfp-results + interval.setSpillState(SpillState.StartInMemory); + } + interval.addMaterializationValue(getMaterializedValue(op, operand, interval)); + + if (Debug.isLogEnabled()) { + Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); + } + } + + /** + * Optimizes moves related to incoming stack based arguments. The interval for the destination + * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot. + */ + void handleMethodArguments(LIRInstruction op) { + if (op instanceof MoveOp) { + MoveOp move = (MoveOp) op; + if (optimizeMethodArgument(move.getInput())) { + StackSlot slot = asStackSlot(move.getInput()); + if (DetailedAsserts.getValue()) { + assert op.id() > 0 : "invalid id"; + assert allocator.blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; + assert isVariable(move.getResult()) : "result of move must be a variable"; + + if (Debug.isLogEnabled()) { + Debug.log("found move from stack slot %s to %s", slot, move.getResult()); + } + } + + Interval interval = allocator.intervalFor(move.getResult()); + interval.setSpillSlot(slot); + interval.assignLocation(slot); + } + } + } + + void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags, final boolean hintAtDef) { + if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) { + + op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> { + if (LinearScan.isVariableOrRegister(registerHint)) { + Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); + Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); + + /* hints always point from def to use */ + if (hintAtDef) { + to.setLocationHint(from); + } else { + from.setLocationHint(to); + } + if (Debug.isLogEnabled()) { + Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); + } + + return registerHint; + } + return null; + }); + } + } + + /** + * Eliminates moves from register to stack if the stack slot is known to be correct. + */ + void changeSpillDefinitionPos(Interval interval, int defPos) { + assert interval.isSplitParent() : "can only be called for split parents"; + + switch (interval.spillState()) { + case NoDefinitionFound: + assert interval.spillDefinitionPos() == -1 : "must no be set before"; + interval.setSpillDefinitionPos(defPos); + interval.setSpillState(SpillState.NoSpillStore); + break; + + case NoSpillStore: + assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; + if (defPos < interval.spillDefinitionPos() - 2) { + // second definition found, so no spill optimization possible for this interval + interval.setSpillState(SpillState.NoOptimization); + } else { + // two consecutive definitions (because of two-operand LIR form) + assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal"; + } + break; + + case NoOptimization: + // nothing to do + break; + + default: + throw new BailoutException("other states not allowed at this time"); + } + } + + private static boolean optimizeMethodArgument(Value value) { + /* + * Object method arguments that are passed on the stack are currently not optimized because + * this requires that the runtime visits method arguments during stack walking. + */ + return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object; + } + + /** + * Determines the register priority for an instruction's output/result operand. + */ + private static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { + if (op instanceof MoveOp) { + MoveOp move = (MoveOp) op; + if (optimizeMethodArgument(move.getInput())) { + return RegisterPriority.None; + } + } else if (op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + if (label.isPhiIn()) { + return RegisterPriority.None; + } + } + + // all other operands require a register + return RegisterPriority.MustHaveRegister; + } + + /** + * Determines the priority which with an instruction's input operand will be allocated a + * register. + */ + private static RegisterPriority registerPriorityOfInputOperand(EnumSet flags) { + if (flags.contains(OperandFlag.STACK)) { + return RegisterPriority.ShouldHaveRegister; + } + // all other operands require a register + return RegisterPriority.MustHaveRegister; + } + + void buildIntervals() { + + try (Indent indent = Debug.logAndIndent("build intervals")) { + InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, true); + } + }; + + InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + int opId = op.id(); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + int opId = op.id(); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + RegisterPriority p = registerPriorityOfInputOperand(flags); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer stateProc = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + int opId = op.id(); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind()); + } + }; + + // create a list with all caller-save registers (cpu, fpu, xmm) + Register[] callerSaveRegs = allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters(); + + // iterate all blocks in reverse order + for (int i = allocator.blockCount() - 1; i >= 0; i--) { + + AbstractBlockBase block = allocator.blockAt(i); + try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { + + List instructions = allocator.ir.getLIRforBlock(block); + final int blockFrom = allocator.getFirstLirInstructionId(block); + int blockTo = allocator.getLastLirInstructionId(block); + + assert blockFrom == instructions.get(0).id(); + assert blockTo == instructions.get(instructions.size() - 1).id(); + + // Update intervals for operands live at the end of this block; + BitSet live = allocator.getBlockData(block).liveOut; + for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { + assert live.get(operandNum) : "should not stop here otherwise"; + AllocatableValue operand = allocator.intervalFor(operandNum).operand; + if (Debug.isLogEnabled()) { + Debug.log("live in %d: %s", operandNum, operand); + } + + addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal); + + /* + * Add special use positions for loop-end blocks when the interval is used + * anywhere inside this loop. It's possible that the block was part of a + * non-natural loop, so it might have an invalid loop index. + */ + if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) { + allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); + } + } + + /* + * Iterate all instructions of the block in reverse order. definitions of + * intervals are processed before uses. + */ + for (int j = instructions.size() - 1; j >= 0; j--) { + final LIRInstruction op = instructions.get(j); + final int opId = op.id(); + + try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { + + // add a temp range for each register if operation destroys + // caller-save registers + if (op.destroysCallerSavedRegisters()) { + for (Register r : callerSaveRegs) { + if (allocator.attributes(r).isAllocatable()) { + addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal); + } + } + if (Debug.isLogEnabled()) { + Debug.log("operation destroys all caller-save registers"); + } + } + + op.visitEachOutput(outputConsumer); + op.visitEachTemp(tempConsumer); + op.visitEachAlive(aliveConsumer); + op.visitEachInput(inputConsumer); + + /* + * Add uses of live locals from interpreter's point of view for proper + * debug information generation. Treat these operands as temp values (if + * the live range is extended to a call site, the value would be in a + * register at the call otherwise). + */ + op.visitEachState(stateProc); + + // special steps for some instructions (especially moves) + handleMethodArguments(op); + + } + + } // end of instruction iteration + } + } // end of block iteration + + /* + * Add the range [0, 1] to all fixed intervals. the register allocator need not handle + * unhandled fixed intervals. + */ + for (Interval interval : allocator.intervals()) { + if (interval != null && isRegister(interval.operand)) { + interval.addRange(0, 1); + } + } + } + } + + /** + * Returns a value for a interval definition, which can be used for re-materialization. + * + * @param op An instruction which defines a value + * @param operand The destination operand of the instruction + * @param interval The interval for this defined value. + * @return Returns the value which is moved to the instruction and which can be reused at all + * reload-locations in case the interval of this instruction is spilled. Currently this + * can only be a {@link JavaConstant}. + */ + static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { + if (op instanceof MoveOp) { + MoveOp move = (MoveOp) op; + if (move.getInput() instanceof JavaConstant) { + /* + * Check if the interval has any uses which would accept an stack location (priority + * == ShouldHaveRegister). Rematerialization of such intervals can result in a + * degradation, because rematerialization always inserts a constant load, even if + * the value is not needed in a register. + */ + Interval.UsePosList usePosList = interval.usePosList(); + int numUsePos = usePosList.size(); + for (int useIdx = 0; useIdx < numUsePos; useIdx++) { + Interval.RegisterPriority priority = usePosList.registerPriority(useIdx); + if (priority == Interval.RegisterPriority.ShouldHaveRegister) { + return null; + } + } + return (JavaConstant) move.getInput(); + } + } + return null; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; + +final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase { + + private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition"); + private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability"); + + private final LinearScan allocator; + + LinearScanOptimizeSpillPositionPhase(LinearScan allocator) { + this.allocator = allocator; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + optimizeSpillPosition(); + allocator.printIntervals("After optimize spill position"); + } + + private void optimizeSpillPosition() { + LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.ir.linearScanOrder().size()]; + for (Interval interval : allocator.intervals()) { + if (interval != null && interval.isSplitParent() && interval.spillState() == SpillState.SpillInDominator) { + AbstractBlockBase defBlock = allocator.blockForId(interval.spillDefinitionPos()); + AbstractBlockBase spillBlock = null; + Interval firstSpillChild = null; + try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) { + for (Interval splitChild : interval.getSplitChildren()) { + if (isStackSlotValue(splitChild.location())) { + if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) { + firstSpillChild = splitChild; + } else { + assert firstSpillChild.from() < splitChild.from(); + } + // iterate all blocks where the interval has use positions + for (AbstractBlockBase splitBlock : blocksForInterval(splitChild)) { + if (dominates(defBlock, splitBlock)) { + if (Debug.isLogEnabled()) { + Debug.log("Split interval %s, block %s", splitChild, splitBlock); + } + if (spillBlock == null) { + spillBlock = splitBlock; + } else { + spillBlock = commonDominator(spillBlock, splitBlock); + assert spillBlock != null; + } + } + } + } + } + if (spillBlock == null) { + // no spill interval + interval.setSpillState(SpillState.StoreAtDefinition); + } else { + // move out of loops + if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) { + spillBlock = moveSpillOutOfLoop(defBlock, spillBlock); + } + + /* + * If the spill block is the begin of the first split child (aka the value + * is on the stack) spill in the dominator. + */ + assert firstSpillChild != null; + if (!defBlock.equals(spillBlock) && spillBlock.equals(allocator.blockForId(firstSpillChild.from()))) { + AbstractBlockBase dom = spillBlock.getDominator(); + if (Debug.isLogEnabled()) { + Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom); + } + spillBlock = dom; + } + + if (!defBlock.equals(spillBlock)) { + assert dominates(defBlock, spillBlock); + betterSpillPos.increment(); + if (Debug.isLogEnabled()) { + Debug.log("Better spill position found (Block %s)", spillBlock); + } + + if (defBlock.probability() <= spillBlock.probability()) { + // better spill block has the same probability -> do nothing + interval.setSpillState(SpillState.StoreAtDefinition); + } else { + LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()]; + if (insertionBuffer == null) { + insertionBuffer = new LIRInsertionBuffer(); + insertionBuffers[spillBlock.getId()] = insertionBuffer; + insertionBuffer.init(allocator.ir.getLIRforBlock(spillBlock)); + } + int spillOpId = allocator.getFirstLirInstructionId(spillBlock); + // insert spill move + AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location(); + AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval); + LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation); + move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID); + /* + * We can use the insertion buffer directly because we always insert + * at position 1. + */ + insertionBuffer.append(1, move); + + betterSpillPosWithLowerProbability.increment(); + interval.setSpillDefinitionPos(spillOpId); + } + } else { + // definition is the best choice + interval.setSpillState(SpillState.StoreAtDefinition); + } + } + } + } + } + for (LIRInsertionBuffer insertionBuffer : insertionBuffers) { + if (insertionBuffer != null) { + assert insertionBuffer.initialized() : "Insertion buffer is nonnull but not initialized!"; + insertionBuffer.finish(); + } + } + } + + /** + * Iterate over all {@link AbstractBlockBase blocks} of an interval. + */ + private class IntervalBlockIterator implements Iterator> { + + Range range; + AbstractBlockBase block; + + public IntervalBlockIterator(Interval interval) { + range = interval.first(); + block = allocator.blockForId(range.from); + } + + public AbstractBlockBase next() { + AbstractBlockBase currentBlock = block; + int nextBlockIndex = block.getLinearScanNumber() + 1; + if (nextBlockIndex < allocator.sortedBlocks.size()) { + block = allocator.sortedBlocks.get(nextBlockIndex); + if (range.to <= allocator.getFirstLirInstructionId(block)) { + range = range.next; + if (range == Range.EndMarker) { + block = null; + } else { + block = allocator.blockForId(range.from); + } + } + } else { + block = null; + } + return currentBlock; + } + + public boolean hasNext() { + return block != null; + } + } + + private Iterable> blocksForInterval(Interval interval) { + return new Iterable>() { + public Iterator> iterator() { + return new IntervalBlockIterator(interval); + } + }; + } + + private static AbstractBlockBase moveSpillOutOfLoop(AbstractBlockBase defBlock, AbstractBlockBase spillBlock) { + int defLoopDepth = defBlock.getLoopDepth(); + for (AbstractBlockBase block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) { + assert block != null : "spill block not dominated by definition block?"; + if (block.getLoopDepth() <= defLoopDepth) { + assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!"; + return block; + } + } + return defBlock; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java Thu May 28 17:44:05 2015 +0200 @@ -48,12 +48,15 @@ }); @Override - protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory) { + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + final LinearScan allocator; if (LinearScanPhase.SSA_LSRA.getValue()) { - new SSALinearScan(target, lirGenRes, spillMoveFactory, new RegisterAllocationConfig(lirGenRes.getFrameMapBuilder().getRegisterConfig())).allocate(); + allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig); } else { - new LinearScan(target, lirGenRes, spillMoveFactory, new RegisterAllocationConfig(lirGenRes.getFrameMapBuilder().getRegisterConfig())).allocate(); + allocator = new LinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig); } + allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.*; +import com.oracle.graal.lir.phases.*; + +final class LinearScanRegisterAllocationPhase extends AllocationPhase { + + private final LinearScan allocator; + + LinearScanRegisterAllocationPhase(LinearScan allocator) { + this.allocator = allocator; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + allocator.printIntervals("Before register allocation"); + allocateRegisters(); + allocator.printIntervals("After register allocation"); + } + + void allocateRegisters() { + try (Indent indent = Debug.logAndIndent("allocate registers")) { + Interval precoloredIntervals; + Interval notPrecoloredIntervals; + + Interval.Pair result = allocator.createUnhandledLists(LinearScan.IS_PRECOLORED_INTERVAL, LinearScan.IS_VARIABLE_INTERVAL); + precoloredIntervals = result.first; + notPrecoloredIntervals = result.second; + + // allocate cpu registers + LinearScanWalker lsw; + if (OptimizingLinearScanWalker.Options.LSRAOptimization.getValue()) { + lsw = new OptimizingLinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals); + } else { + lsw = new LinearScanWalker(allocator, precoloredIntervals, notPrecoloredIntervals); + } + lsw.walk(); + lsw.finishAllocation(); + } + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.compiler.common.GraalOptions.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; + +/** + * Phase 6: resolve data flow + * + * Insert moves at edges between blocks if intervals have been split. + */ +class LinearScanResolveDataFlowPhase extends AllocationPhase { + + protected final LinearScan allocator; + + LinearScanResolveDataFlowPhase(LinearScan allocator) { + this.allocator = allocator; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + resolveDataFlow(); + } + + void resolveCollectMappings(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, AbstractBlockBase midBlock, MoveResolver moveResolver) { + assert moveResolver.checkEmpty(); + assert midBlock == null || + (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals( + toBlock)); + + int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock); + int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1; + int numOperands = allocator.operandSize(); + BitSet liveAtEdge = allocator.getBlockData(toBlock).liveIn; + + // visit all variables for which the liveAtEdge bit is set + for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { + assert operandNum < numOperands : "live information set for not exisiting interval"; + assert allocator.getBlockData(fromBlock).liveOut.get(operandNum) && allocator.getBlockData(toBlock).liveIn.get(operandNum) : "interval not live at this edge"; + + Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF); + Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); + + if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { + // need to insert move instruction + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + + void resolveFindInsertPos(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, MoveResolver moveResolver) { + if (fromBlock.getSuccessorCount() <= 1) { + if (Debug.isLogEnabled()) { + Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId()); + } + + List instructions = allocator.ir.getLIRforBlock(fromBlock); + LIRInstruction instr = instructions.get(instructions.size() - 1); + if (instr instanceof StandardOp.JumpOp) { + // insert moves before branch + moveResolver.setInsertPosition(instructions, instructions.size() - 1); + } else { + moveResolver.setInsertPosition(instructions, instructions.size()); + } + + } else { + if (Debug.isLogEnabled()) { + Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId()); + } + + if (DetailedAsserts.getValue()) { + assert allocator.ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; + + /* + * Because the number of predecessor edges matches the number of successor edges, + * blocks which are reached by switch statements may have be more than one + * predecessor but it will be guaranteed that all predecessors will be the same. + */ + for (AbstractBlockBase predecessor : toBlock.getPredecessors()) { + assert fromBlock == predecessor : "all critical edges must be broken"; + } + } + + moveResolver.setInsertPosition(allocator.ir.getLIRforBlock(toBlock), 1); + } + } + + /** + * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that + * have been split. + */ + void resolveDataFlow() { + try (Indent indent = Debug.logAndIndent("resolve data flow")) { + + int numBlocks = allocator.blockCount(); + MoveResolver moveResolver = allocator.createMoveResolver(); + BitSet blockCompleted = new BitSet(numBlocks); + BitSet alreadyResolved = new BitSet(numBlocks); + + for (AbstractBlockBase block : allocator.sortedBlocks) { + + // check if block has only one predecessor and only one successor + if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { + List instructions = allocator.ir.getLIRforBlock(block); + assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; + + // check if block is empty (only label and branch) + if (instructions.size() == 2) { + AbstractBlockBase pred = block.getPredecessors().iterator().next(); + AbstractBlockBase sux = block.getSuccessors().iterator().next(); + + // prevent optimization of two consecutive blocks + if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { + if (Debug.isLogEnabled()) { + Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); + } + + blockCompleted.set(block.getLinearScanNumber()); + + /* + * Directly resolve between pred and sux (without looking at the empty + * block between). + */ + resolveCollectMappings(pred, sux, block, moveResolver); + if (moveResolver.hasMappings()) { + moveResolver.setInsertPosition(instructions, 1); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } + + for (AbstractBlockBase fromBlock : allocator.sortedBlocks) { + if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { + alreadyResolved.clear(); + alreadyResolved.or(blockCompleted); + + for (AbstractBlockBase toBlock : fromBlock.getSuccessors()) { + + /* + * Check for duplicate edges between the same blocks (can happen with switch + * blocks). + */ + if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { + if (Debug.isLogEnabled()) { + Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); + } + + alreadyResolved.set(toBlock.getLinearScanNumber()); + + // collect all intervals that have been split between + // fromBlock and toBlock + resolveCollectMappings(fromBlock, toBlock, null, moveResolver); + if (moveResolver.hasMappings()) { + resolveFindInsertPos(fromBlock, toBlock, moveResolver); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } + + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java Thu May 28 17:44:05 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; @@ -50,6 +51,10 @@ private MoveResolver moveResolver; // for ordering spill moves + private int minReg; + + private int maxReg; + /** * Only 10% of the lists in {@link #spillIntervals} are actually used. But when they are used, * they can grow quite long. The maximum length observed was 45 (all numbers taken from a @@ -95,10 +100,22 @@ } } + int maxRegisterNumber() { + return maxReg; + } + + int minRegisterNumber() { + return minReg; + } + + boolean isRegisterInRange(int reg) { + return reg >= minRegisterNumber() && reg <= maxRegisterNumber(); + } + void excludeFromUse(Interval i) { Value location = i.location(); int i1 = asRegister(location).number; - if (i1 >= availableRegs[0].number && i1 <= availableRegs[availableRegs.length - 1].number) { + if (isRegisterInRange(i1)) { usePos[i1] = 0; } } @@ -107,7 +124,7 @@ if (usePos != -1) { assert usePos != 0 : "must use excludeFromUse to set usePos to 0"; int i = asRegister(interval.location()).number; - if (i >= availableRegs[0].number && i <= availableRegs[availableRegs.length - 1].number) { + if (isRegisterInRange(i)) { if (this.usePos[i] > usePos) { this.usePos[i] = usePos; } @@ -126,7 +143,7 @@ void setBlockPos(Interval i, int blockPos) { if (blockPos != -1) { int reg = asRegister(i.location()).number; - if (reg >= availableRegs[0].number && reg <= availableRegs[availableRegs.length - 1].number) { + if (isRegisterInRange(reg)) { if (this.blockPos[reg] > blockPos) { this.blockPos[reg] = blockPos; } @@ -483,7 +500,7 @@ allocator.assignSpillSlot(interval); handleSpillSlot(interval); - allocator.changeSpillState(interval, minSplitPos); + changeSpillState(interval, minSplitPos); // Also kick parent intervals out of register to memory when they have no use // position. This avoids short interval in register surrounded by intervals in @@ -529,7 +546,7 @@ Interval spilledPart = interval.split(optimalSplitPos, allocator); allocator.assignSpillSlot(spilledPart); handleSpillSlot(spilledPart); - allocator.changeSpillState(spilledPart, optimalSplitPos); + changeSpillState(spilledPart, optimalSplitPos); if (!allocator.isBlockBegin(optimalSplitPos)) { if (Debug.isLogEnabled()) { @@ -551,6 +568,59 @@ } } + // called during register allocation + private void changeSpillState(Interval interval, int spillPos) { + switch (interval.spillState()) { + case NoSpillStore: { + int defLoopDepth = allocator.blockForId(interval.spillDefinitionPos()).getLoopDepth(); + int spillLoopDepth = allocator.blockForId(spillPos).getLoopDepth(); + + if (defLoopDepth < spillLoopDepth) { + /* + * The loop depth of the spilling position is higher then the loop depth at the + * definition of the interval. Move write to memory out of loop. + */ + if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + // find best spill position in dominator the tree + interval.setSpillState(SpillState.SpillInDominator); + } else { + // store at definition of the interval + interval.setSpillState(SpillState.StoreAtDefinition); + } + } else { + /* + * The interval is currently spilled only once, so for now there is no reason to + * store the interval at the definition. + */ + interval.setSpillState(SpillState.OneSpillStore); + } + break; + } + + case OneSpillStore: { + if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + // the interval is spilled more then once + interval.setSpillState(SpillState.SpillInDominator); + } else { + // It is better to store it to memory at the definition. + interval.setSpillState(SpillState.StoreAtDefinition); + } + break; + } + + case SpillInDominator: + case StoreAtDefinition: + case StartInMemory: + case NoOptimization: + case NoDefinitionFound: + // nothing to do + break; + + default: + throw new BailoutException("other states not allowed at this time"); + } + } + /** * This is called for every interval that is assigned to a stack slot. */ @@ -643,8 +713,7 @@ Register minFullReg = null; Register maxPartialReg = null; - for (int i = 0; i < availableRegs.length; ++i) { - Register availableReg = availableRegs[i]; + for (Register availableReg : availableRegs) { int number = availableReg.number; if (usePos[number] >= intervalTo) { // this register is free for the full interval @@ -805,7 +874,10 @@ } void initVarsForAlloc(Interval interval) { - availableRegs = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind()); + AllocatableRegisters allocatableRegisters = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind()); + availableRegs = allocatableRegisters.allocatableRegisters; + minReg = allocatableRegisters.minRegisterNumber; + maxReg = allocatableRegisters.maxRegisterNumber; } static boolean isMove(LIRInstruction op, Interval from, Interval to) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; @@ -53,7 +54,8 @@ } @Override - protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory) { + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java Thu May 28 17:44:05 2015 +0200 @@ -198,7 +198,7 @@ Value location = to.location(); if (mightBeBlocked(location)) { - if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !location.equals(fromReg)))) { + if ((valueBlocked(location) > 1 || (valueBlocked(location) == 1 && !isMoveToSelf(fromReg, location)))) { return false; } } @@ -206,6 +206,18 @@ return true; } + protected boolean isMoveToSelf(Value from, Value to) { + assert to != null; + if (to.equals(from)) { + return true; + } + if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) { + assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from); + return true; + } + return false; + } + protected boolean mightBeBlocked(Value location) { return isRegister(location); } @@ -226,7 +238,7 @@ private void insertMove(Interval fromInterval, Interval toInterval) { assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval; - assert fromInterval.kind().equals(toInterval.kind()) : "move between different types"; + assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types"; assert insertIdx != -1 : "must setup insert position first"; insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location())); @@ -247,7 +259,7 @@ } private void insertMove(Value fromOpr, Interval toInterval) { - assert fromOpr.getLIRKind().equals(toInterval.kind()) : format("move between different types %s %s", fromOpr.getLIRKind(), toInterval.kind()); + assert LIRKind.verifyMoveKinds(toInterval.kind(), fromOpr.getLIRKind()) : format("move between different types %s %s", fromOpr.getLIRKind(), toInterval.kind()); assert insertIdx != -1 : "must setup insert position first"; AllocatableValue toOpr = toInterval.operand; @@ -409,8 +421,8 @@ } assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval; - assert fromInterval.kind().equals(toInterval.kind()) || (fromInterval.kind().getPlatformKind().equals(toInterval.kind().getPlatformKind()) && toInterval.kind().isDerivedReference()) : String.format( - "Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval, toInterval); + assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval, + toInterval); mappingFrom.add(fromInterval); mappingFromOpr.add(Value.ILLEGAL); mappingTo.add(toInterval); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.ssa.*; +import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor; + +class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase { + + private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]"); + private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]"); + + SSALinarScanResolveDataFlowPhase(LinearScan allocator) { + super(allocator); + } + + @Override + void resolveCollectMappings(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, AbstractBlockBase midBlock, MoveResolver moveResolver) { + super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); + + if (toBlock.getPredecessorCount() > 1) { + int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock); + int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1; + + AbstractBlockBase phiOutBlock = midBlock != null ? midBlock : fromBlock; + List instructions = allocator.ir.getLIRforBlock(phiOutBlock); + int phiOutIdx = SSAUtils.phiOutIndex(allocator.ir, phiOutBlock); + int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id(); + assert phiOutId >= 0; + + PhiValueVisitor visitor = new PhiValueVisitor() { + + public void visit(Value phiIn, Value phiOut) { + assert !isRegister(phiOut) : "phiOut is a register: " + phiOut; + assert !isRegister(phiIn) : "phiIn is a register: " + phiIn; + Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); + if (isConstant(phiOut)) { + numPhiResolutionMoves.increment(); + moveResolver.addMapping(phiOut, toInterval); + } else { + Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF); + if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { + numPhiResolutionMoves.increment(); + if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { + moveResolver.addMapping(fromInterval, toInterval); + } else { + numStackToStackMoves.increment(); + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + } + }; + + SSAUtils.forEachPhiValuePair(allocator.ir, toBlock, phiOutBlock, visitor); + SSAUtils.removePhiOut(allocator.ir, phiOutBlock); + } + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java Thu May 28 17:44:05 2015 +0200 @@ -22,32 +22,17 @@ */ package com.oracle.graal.lir.alloc.lsra; -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRValueUtil.*; - -import java.util.*; - import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.OperandFlag; -import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.StandardOp.LabelOp; -import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.ssa.*; -import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor; final class SSALinearScan extends LinearScan { - private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]"); - private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]"); - SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig) { super(target, res, spillMoveFactory, regAllocConfig); } @@ -60,50 +45,18 @@ } @Override - protected int firstInstructionOfInterest() { - // also look at Labels as they define PHI values - return 0; + protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { + return new SSALinearScanLifetimeAnalysisPhase(this); } @Override - void resolveCollectMappings(AbstractBlockBase fromBlock, AbstractBlockBase toBlock, AbstractBlockBase midBlock, MoveResolver moveResolver) { - super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); - - if (toBlock.getPredecessorCount() > 1) { - int toBlockFirstInstructionId = getFirstLirInstructionId(toBlock); - int fromBlockLastInstructionId = getLastLirInstructionId(fromBlock) + 1; - - AbstractBlockBase phiOutBlock = midBlock != null ? midBlock : fromBlock; - List instructions = ir.getLIRforBlock(phiOutBlock); - int phiOutIdx = SSAUtils.phiOutIndex(ir, phiOutBlock); - int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id(); - assert phiOutId >= 0; - - PhiValueVisitor visitor = new PhiValueVisitor() { + protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { + return new SSALinarScanResolveDataFlowPhase(this); + } - public void visit(Value phiIn, Value phiOut) { - Interval toInterval = splitChildAtOpId(intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); - if (isConstant(phiOut)) { - numPhiResolutionMoves.increment(); - moveResolver.addMapping(phiOut, toInterval); - } else { - Interval fromInterval = splitChildAtOpId(intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF); - if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { - numPhiResolutionMoves.increment(); - if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { - moveResolver.addMapping(fromInterval, toInterval); - } else { - numStackToStackMoves.increment(); - moveResolver.addMapping(fromInterval, toInterval); - } - } - } - } - }; - - SSAUtils.forEachPhiValuePair(ir, toBlock, phiOutBlock, visitor); - SSAUtils.removePhiOut(ir, phiOutBlock); - } + @Override + protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { + return new SSALinearScanEliminateSpillMovePhase(this); } @Override @@ -121,80 +74,4 @@ } } - @Override - protected boolean canEliminateSpillMove(AbstractBlockBase block, MoveOp move) { - // SSA Linear Scan might introduce moves to stack slots - assert isVariable(move.getResult()) || LinearScanPhase.SSA_LSRA.getValue() : "Move should not be produced in a non-SSA compilation: " + move; - - Interval curInterval = intervalFor(move.getResult()); - - if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory() && !isPhiResolutionMove(block, move, curInterval)) { - assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); - return true; - } - return false; - } - - @Override - void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags, final boolean hintAtDef) { - super.addRegisterHint(op, targetValue, mode, flags, hintAtDef); - - if (hintAtDef && op instanceof LabelOp) { - LabelOp label = (LabelOp) op; - - Interval to = getOrCreateInterval((AllocatableValue) targetValue); - - SSAUtils.forEachPhiRegisterHint(ir, blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> { - if (isVariableOrRegister(registerHint)) { - Interval from = getOrCreateInterval((AllocatableValue) registerHint); - - setHint(op, to, from); - setHint(op, from, to); - } - }); - } - } - - private static void setHint(final LIRInstruction op, Interval target, Interval source) { - Interval currentHint = target.locationHint(false); - if (currentHint == null || currentHint.from() > target.from()) { - /* - * Update hint if there was none or if the hint interval starts after the hinted - * interval. - */ - target.setLocationHint(source); - if (Debug.isLogEnabled()) { - Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber); - } - } - } - - private boolean isPhiResolutionMove(AbstractBlockBase block, MoveOp move, Interval toInterval) { - if (!LinearScanPhase.SSA_LSRA.getValue()) { - return false; - } - if (!toInterval.isSplitParent()) { - return false; - } - if ((toInterval.from() & 1) == 1) { - // phi intervals start at even positions. - return false; - } - if (block.getSuccessorCount() != 1) { - return false; - } - LIRInstruction op = instructionForId(toInterval.from()); - if (!(op instanceof LabelOp)) { - return false; - } - AbstractBlockBase intStartBlock = blockForId(toInterval.from()); - assert ir.getLIRforBlock(intStartBlock).get(0).equals(op); - if (!block.getSuccessors().get(0).equals(intStartBlock)) { - return false; - } - try (Indent indet = Debug.indent()) { - Debug.log("Is a move (%s) to phi interval %s", move, toInterval); - } - return true; - } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRValueUtil.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.MoveOp; + +public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase { + + SSALinearScanEliminateSpillMovePhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected int firstInstructionOfInterest() { + // also look at Labels as they define PHI values + return 0; + } + + @Override + protected boolean canEliminateSpillMove(AbstractBlockBase block, MoveOp move) { + // SSA Linear Scan might introduce moves to stack slots + assert isVariable(move.getResult()) || LinearScanPhase.SSA_LSRA.getValue() : "Move should not be produced in a non-SSA compilation: " + move; + + Interval curInterval = allocator.intervalFor(move.getResult()); + + if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory() && !isPhiResolutionMove(block, move, curInterval)) { + assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); + return true; + } + return false; + } + + private boolean isPhiResolutionMove(AbstractBlockBase block, MoveOp move, Interval toInterval) { + if (!LinearScanPhase.SSA_LSRA.getValue()) { + return false; + } + if (!toInterval.isSplitParent()) { + return false; + } + if ((toInterval.from() & 1) == 1) { + // phi intervals start at even positions. + return false; + } + if (block.getSuccessorCount() != 1) { + return false; + } + LIRInstruction op = allocator.instructionForId(toInterval.from()); + if (!(op instanceof LabelOp)) { + return false; + } + AbstractBlockBase intStartBlock = allocator.blockForId(toInterval.from()); + assert allocator.ir.getLIRforBlock(intStartBlock).get(0).equals(op); + if (!block.getSuccessors().get(0).equals(intStartBlock)) { + return false; + } + try (Indent indet = Debug.indent()) { + Debug.log("Is a move (%s) to phi interval %s", move, toInterval); + } + return true; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2015, 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.alloc.lsra; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.ssa.*; + +public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase { + + SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) { + super(linearScan); + } + + @Override + void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags, final boolean hintAtDef) { + super.addRegisterHint(op, targetValue, mode, flags, hintAtDef); + + if (hintAtDef && op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + + Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); + + SSAUtils.forEachPhiRegisterHint(allocator.ir, allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> { + if (LinearScan.isVariableOrRegister(registerHint)) { + Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); + + setHint(op, to, from); + setHint(op, from, to); + } + }); + } + } + + private static void setHint(final LIRInstruction op, Interval target, Interval source) { + Interval currentHint = target.locationHint(false); + if (currentHint == null || currentHint.from() > target.from()) { + /* + * Update hint if there was none or if the hint interval starts after the hinted + * interval. + */ + target.setLocationHint(source); + if (Debug.isLogEnabled()) { + Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber); + } + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -38,6 +38,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.options.*; /** * Fills in a {@link CompilationResult} as its code is being assembled. @@ -46,6 +47,11 @@ */ public class CompilationResultBuilder { + // @formatter:off + @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug) + public static final OptionValue PrintLIRWithAssembly = new OptionValue<>(false); + // @formatter:on + private static class ExceptionInfo { public final int codeOffset; @@ -353,12 +359,12 @@ } private void emitBlock(AbstractBlockBase block) { - if (Debug.isDumpEnabled()) { + if (Debug.isDumpEnabled() || PrintLIRWithAssembly.getValue()) { blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); } for (LIRInstruction op : lir.getLIRforBlock(block)) { - if (Debug.isDumpEnabled()) { + if (Debug.isDumpEnabled() || PrintLIRWithAssembly.getValue()) { blockComment(String.format("%d %s", op.id(), op)); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/SimpleVirtualStackSlot.java Thu May 28 17:44:05 2015 +0200 @@ -30,8 +30,6 @@ */ public class SimpleVirtualStackSlot extends VirtualStackSlot { - private static final long serialVersionUID = 7654295701165421750L; - public SimpleVirtualStackSlot(int id, LIRKind lirKind) { super(id, lirKind); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/VirtualStackSlotRange.java Thu May 28 17:44:05 2015 +0200 @@ -33,7 +33,6 @@ */ public class VirtualStackSlotRange extends VirtualStackSlot { - private static final long serialVersionUID = 5152592950118317121L; private final BitSet objects; private final int slots; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java Thu May 28 17:44:05 2015 +0200 @@ -25,26 +25,29 @@ import java.util.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.lir.gen.*; -import com.oracle.graal.lir.gen.LIRGeneratorTool.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; public abstract class AllocationPhase extends LIRPhase { public static final class AllocationContext { private final SpillMoveFactory spillMoveFactory; + private final RegisterAllocationConfig registerAllocationConfig; - public AllocationContext(SpillMoveFactory spillMoveFactory) { + public AllocationContext(SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) { this.spillMoveFactory = spillMoveFactory; + this.registerAllocationConfig = registerAllocationConfig; } } @Override protected final > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, AllocationContext context) { - run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory); + run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory, context.registerAllocationConfig); } protected abstract > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, - SpillMoveFactory spillMoveFactory); + SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java Thu May 28 17:44:05 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -69,7 +70,8 @@ private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]"); @Override - protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory) { + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { lirGenRes.buildFrameMap(this); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -40,7 +41,8 @@ public class SimpleStackSlotAllocator extends AllocationPhase implements StackSlotAllocator { @Override - protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory) { + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { lirGenRes.buildFrameMap(this); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java Thu May 28 17:44:05 2015 +0200 @@ -99,7 +99,7 @@ @Override public String toString() { - return String.format("SI[%d-%d] k=%s o=%s l=%s h=%s", from, to, kind, operand, location, hint.getOperand()); + return String.format("SI[%d-%d] k=%s o=%s l=%s h=%s", from, to, kind, operand, location, hint != null ? hint.getOperand() : "null"); } public void setLocationHint(StackInterval locationHint) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedConvertedInductionVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedConvertedInductionVariable.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, 2015, 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.loop; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +public class DerivedConvertedInductionVariable extends DerivedInductionVariable { + + private final Stamp stamp; + private final ValueNode value; + + public DerivedConvertedInductionVariable(LoopEx loop, InductionVariable base, Stamp stamp, ValueNode value) { + super(loop, base); + this.stamp = stamp; + this.value = value; + } + + @Override + public ValueNode valueNode() { + return value; + } + + @Override + public Direction direction() { + return base.direction(); + } + + @Override + public ValueNode initNode() { + return IntegerConvertNode.convert(base.initNode(), stamp, graph()); + } + + @Override + public ValueNode strideNode() { + return IntegerConvertNode.convert(base.strideNode(), stamp, graph()); + } + + @Override + public boolean isConstantInit() { + return base.isConstantInit(); + } + + @Override + public boolean isConstantStride() { + return base.isConstantStride(); + } + + @Override + public long constantInit() { + return base.constantInit(); + } + + @Override + public long constantStride() { + return base.constantStride(); + } + + @Override + public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp s) { + return base.extremumNode(assumePositiveTripCount, s); + } + + @Override + public ValueNode exitValueNode() { + return IntegerConvertNode.convert(base.exitValueNode(), stamp, graph()); + } + + @Override + public boolean isConstantExtremum() { + return base.isConstantExtremum(); + } + + @Override + public long constantExtremum() { + return base.constantExtremum(); + } + + @Override + public void deleteUnusedNodes() { + } + + @Override + public String toString() { + return String.format("DerivedConvertedInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), stamp); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java Thu May 28 17:44:05 2015 +0200 @@ -42,7 +42,7 @@ public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) { super(loop, base); - this.scale = ConstantNode.forInt(-1, value.graph()); + this.scale = ConstantNode.forIntegerStamp(value.stamp(), -1, value.graph()); this.value = value; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -162,7 +162,7 @@ public boolean detectCounted() { LoopBeginNode loopBegin = loopBegin(); FixedNode next = loopBegin.next(); - while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode) { + while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode || next instanceof InfopointNode) { next = ((FixedWithNextNode) next).next(); } if (next instanceof IfNode) { @@ -333,6 +333,16 @@ iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op); } else if ((scale = mul(loop, op, baseIvNode)) != null) { iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op); + } else { + boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode; + if (!isValidConvert && op instanceof ZeroExtendNode) { + IntegerStamp inputStamp = (IntegerStamp) ((ZeroExtendNode) op).getValue().stamp(); + isValidConvert = inputStamp.isPositive(); + } + + if (isValidConvert) { + iv = new DerivedConvertedInductionVariable(loop, baseIv, op.stamp(), op); + } } if (iv != null) { @@ -368,7 +378,7 @@ if (op instanceof LeftShiftNode) { LeftShiftNode shift = (LeftShiftNode) op; if (shift.getX() == base && shift.getY().isConstant()) { - return ConstantNode.forInt(1 << shift.getY().asJavaConstant().asInt(), base.graph()); + return ConstantNode.forIntegerStamp(base.stamp(), 1 << shift.getY().asJavaConstant().asInt(), base.graph()); } } return null; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.VirtualState.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.util.*; public class LoopFragmentInside extends LoopFragment { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java --- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -123,8 +123,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Input list field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Input list field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Input list field must not be public"); } } else { if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) { @@ -133,8 +133,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Input field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Input field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Input field must not be public"); } } } else if (isSuccessor) { @@ -152,8 +152,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Successor field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Successor field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Successor field must not be public"); } } @@ -167,12 +167,8 @@ if (isAssignableWithErasure(field, NodeSuccessorList)) { throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName()); } - if (modifiers.contains(PUBLIC)) { - if (!modifiers.contains(FINAL)) { - throw new ElementException(field, "Data field must be final if public otherwise it must be protected"); - } - } else if (!modifiers.contains(PROTECTED)) { - throw new ElementException(field, "Data field must be protected"); + if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) { + throw new ElementException(field, "Data field must be final if public"); } } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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.nodes; - -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.extended.*; - -/** - * Provides an implementation of {@link StateSplit}. - */ -@NodeInfo -public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint { - - public static final NodeClass TYPE = NodeClass.create(AbstractMemoryCheckpoint.class); - - protected AbstractMemoryCheckpoint(NodeClass c, Stamp stamp) { - this(c, stamp, null); - } - - protected AbstractMemoryCheckpoint(NodeClass c, Stamp stamp, FrameState stateAfter) { - super(c, stamp, stateAfter); - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,10 +31,14 @@ import com.oracle.graal.nodeinfo.*; @NodeInfo -public abstract class DirectCallTargetNode extends LoweredCallTargetNode { +public class DirectCallTargetNode extends LoweredCallTargetNode { public static final NodeClass TYPE = NodeClass.create(DirectCallTargetNode.class); + public DirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { + this(TYPE, arguments, returnStamp, signature, target, callType, invokeKind); + } + protected DirectCallTargetNode(NodeClass c, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { super(c, arguments, returnStamp, signature, target, callType, invokeKind); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu May 28 17:44:05 2015 +0200 @@ -117,6 +117,19 @@ bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; } + /** + * Creates a placeholder frame state with a single element on the stack representing a return + * value. This allows the parsing of an intrinsic to communicate the returned value in a + * {@link StateSplit#stateAfter() stateAfter} to the inlining call site. + * + * @param bci this must be {@link BytecodeFrame#AFTER_BCI} + */ + public FrameState(int bci, ValueNode returnValue) { + this(null, null, bci, 0, returnValue.getKind().getSlotCount(), 0, false, false, null, Collections. emptyList()); + assert bci == BytecodeFrame.AFTER_BCI; + this.values.initialize(0, returnValue); + } + public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List monitorIds, boolean rethrowException, boolean duringCall) { this(outerFrameState, method, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections. emptyList()); @@ -153,6 +166,17 @@ this.outerFrameState = x; } + public BytecodePosition toBytecodePosition() { + return toBytecodePosition(this); + } + + public static BytecodePosition toBytecodePosition(FrameState fs) { + if (fs == null) { + return null; + } + return new BytecodePosition(toBytecodePosition(fs.outerFrameState()), fs.method(), fs.bci); + } + /** * @see BytecodeFrame#rethrowException */ @@ -410,7 +434,11 @@ String nl = CodeUtil.NEW_LINE; FrameState fs = frameState; while (fs != null) { - MetaUtil.appendLocation(sb, fs.method, fs.bci).append(nl); + MetaUtil.appendLocation(sb, fs.method, fs.bci); + if (BytecodeFrame.isPlaceholderBci(fs.bci)) { + sb.append("//").append(getPlaceholderBciName(fs.bci)); + } + sb.append(nl); sb.append("locals: ["); for (int i = 0; i < fs.localsSize(); i++) { sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id)); @@ -434,7 +462,11 @@ if (verbosity == Verbosity.Debugger) { return toString(this); } else if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "@" + bci; + String res = super.toString(Verbosity.Name) + "@" + bci; + if (BytecodeFrame.isPlaceholderBci(bci)) { + res += "[" + getPlaceholderBciName(bci) + "]"; + } + return res; } else { return super.toString(verbosity); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Thu May 28 17:44:05 2015 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.util.*; /** * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for @@ -272,6 +271,13 @@ LoopScope loopScope = new LoopScope(methodScope); FixedNode firstNode; if (startNode != null) { + /* + * The start node of a graph can be referenced as the guard for a GuardedNode. We + * register the previous block node, so that such guards are correctly anchored when + * doing inlining during graph decoding. + */ + registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false); + firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID); startNode.setNext(firstNode); loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID); @@ -333,6 +339,10 @@ ((AbstractMergeNode) node).forwardEndCount() == 1) { AbstractMergeNode merge = (AbstractMergeNode) node; EndNode singleEnd = merge.forwardEndAt(0); + + /* Nodes that would use this merge as the guard need to use the previous block. */ + registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false); + FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET); singleEnd.replaceAtPredecessor(next); @@ -409,7 +419,7 @@ methodScope.unwindNode = (UnwindNode) node; } else { - simplifyFixedNode(methodScope, loopScope, nodeOrderId, node); + handleFixedNode(methodScope, loopScope, nodeOrderId, node); } return resultScope; @@ -527,7 +537,7 @@ * @param nodeOrderId The orderId of the node. * @param node The node to be simplified. */ - protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { + protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { } protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) { @@ -823,7 +833,13 @@ protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { long readerByteIndex = methodScope.reader.getByteIndex(); Node node = instantiateNode(methodScope, nodeOrderId); - assert !(node instanceof FixedNode); + if (node instanceof FixedNode) { + /* + * This is a severe error that will lead to a corrupted graph, so it is better not to + * continue decoding at all. + */ + throw shouldNotReachHere("Not a floating node: " + node.getClass().getName()); + } /* Read the properties of the node. */ readProperties(methodScope, node); @@ -1154,32 +1170,14 @@ } } + /** + * Removes unnecessary nodes from the graph after decoding. + * + * @param methodScope The current method. + * @param start Marker for the begin of the current method in the graph. + */ protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { assert verifyEdges(methodScope); - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (node instanceof MergeNode) { - MergeNode mergeNode = (MergeNode) node; - if (mergeNode.forwardEndCount() == 1) { - methodScope.graph.reduceTrivialMerge(mergeNode); - } - } - } - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (node instanceof BeginNode || node instanceof KillingBeginNode) { - if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) { - GraphUtil.unlinkFixedNode((AbstractBeginNode) node); - node.safeDelete(); - } - } - } - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (!(node instanceof FixedNode) && node.hasNoUsages()) { - GraphUtil.killCFG(node); - } - } } protected boolean verifyEdges(MethodScope methodScope) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Thu May 28 17:44:05 2015 +0200 @@ -81,6 +81,15 @@ this.negated = negateCondition; } + public static ValueNode createNullCheck(ValueNode object) { + ObjectStamp objectStamp = (ObjectStamp) object.stamp(); + if (objectStamp.nonNull()) { + return object; + } else { + return new GuardingPiNode(object); + } + } + @Override public void lower(LoweringTool tool) { GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/HeapAccess.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +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.nodes; - -/** - * Encapsulates properties of a node describing how it accesses the heap. - */ -public interface HeapAccess { - - /** - * The types of (write/read) barriers attached to stores. - */ - public enum BarrierType { - /** - * Primitive stores which do not necessitate barriers. - */ - NONE, - /** - * Array object stores which necessitate precise barriers. - */ - PRECISE, - /** - * Field object stores which necessitate imprecise barriers. - */ - IMPRECISE - } - - /** - * Gets the write barrier type for that particular access. - */ - BarrierType getBarrierType(); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,11 +31,16 @@ import com.oracle.graal.nodeinfo.*; @NodeInfo -public abstract class IndirectCallTargetNode extends LoweredCallTargetNode { +public class IndirectCallTargetNode extends LoweredCallTargetNode { public static final NodeClass TYPE = NodeClass.create(IndirectCallTargetNode.class); @Input protected ValueNode computedAddress; + public IndirectCallTargetNode(ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, + InvokeKind invokeKind) { + this(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind); + } + protected IndirectCallTargetNode(NodeClass c, ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { super(c, arguments, returnStamp, signature, target, callType, invokeKind); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu May 28 17:44:05 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu May 28 17:44:05 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java Thu May 28 17:44:05 2015 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; @NodeInfo(allowedUsageTypes = {InputType.Memory}) public final class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java Thu May 28 17:44:05 2015 +0200 @@ -55,4 +55,22 @@ public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) { return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability)); } + + public final boolean isTautology() { + if (this instanceof LogicConstantNode) { + LogicConstantNode logicConstantNode = (LogicConstantNode) this; + return logicConstantNode.getValue(); + } + + return false; + } + + public final boolean isContradiction() { + if (this instanceof LogicConstantNode) { + LogicConstantNode logicConstantNode = (LogicConstantNode) this; + return !logicConstantNode.getValue(); + } + + return false; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMap.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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.nodes; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.extended.*; - -/** - * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the - * location. - */ -public interface MemoryMap { - - /** - * Gets the last node that that (potentially) wrote to {@code locationIdentity}. - */ - MemoryNode getLastLocationAccess(LocationIdentity locationIdentity); - - /** - * Gets the location identities in the domain of this map. - */ - Collection getLocations(); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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 static com.oracle.graal.api.meta.LocationIdentity.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -@NodeInfo(allowedUsageTypes = {InputType.Extension, InputType.Memory}) -public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(MemoryMapNode.class); - protected final List locationIdentities; - @Input(InputType.Memory) NodeInputList nodes; - - private boolean checkOrder(Map mmap) { - for (int i = 0; i < locationIdentities.size(); i++) { - LocationIdentity locationIdentity = locationIdentities.get(i); - ValueNode n = nodes.get(i); - assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map"); - } - return true; - } - - public MemoryMapNode(Map mmap) { - super(TYPE, StampFactory.forVoid()); - locationIdentities = new ArrayList<>(mmap.keySet()); - nodes = new NodeInputList<>(this, mmap.values()); - assert checkOrder(mmap); - } - - public boolean isEmpty() { - if (locationIdentities.isEmpty()) { - return true; - } - if (locationIdentities.size() == 1) { - if (nodes.get(0) instanceof StartNode) { - return true; - } - } - return false; - } - - public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) { - if (locationIdentity.isImmutable()) { - return null; - } else { - int index = locationIdentities.indexOf(locationIdentity); - if (index == -1) { - index = locationIdentities.indexOf(any()); - } - assert index != -1; - return (MemoryNode) nodes.get(index); - } - } - - public Collection getLocations() { - return locationIdentities; - } - - public Map toMap() { - HashMap res = CollectionsFactory.newMap(locationIdentities.size()); - for (int i = 0; i < nodes.size(); i++) { - res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i)); - } - return res; - } - - public void generate(NodeLIRBuilderTool generator) { - // nothing to do... - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2009, 2015, 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.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.extended.*; - -/** - * Memory {@code PhiNode}s merge memory dependencies at control flow merges. - */ -@NodeInfo(nameTemplate = "\u03D5({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) -public final class MemoryPhiNode extends PhiNode implements MemoryNode { - - public static final NodeClass TYPE = NodeClass.create(MemoryPhiNode.class); - @Input(InputType.Memory) NodeInputList values; - protected final LocationIdentity locationIdentity; - - public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) { - super(TYPE, StampFactory.forVoid(), merge); - this.locationIdentity = locationIdentity; - this.values = new NodeInputList<>(this); - } - - public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) { - super(TYPE, StampFactory.forVoid(), merge); - this.locationIdentity = locationIdentity; - this.values = new NodeInputList<>(this, values); - } - - public LocationIdentity getLocationIdentity() { - return locationIdentity; - } - - @Override - public NodeInputList values() { - return values; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Thu May 28 17:44:05 2015 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; @NodeInfo diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java Thu May 28 17:44:05 2015 +0200 @@ -48,15 +48,7 @@ } public void addCaller(BytecodePosition caller) { - this.position = relink(this.position, caller); - } - - private static BytecodePosition relink(BytecodePosition position, BytecodePosition link) { - if (position.getCaller() == null) { - return new BytecodePosition(link, position.getMethod(), position.getBCI()); - } else { - return new BytecodePosition(relink(position.getCaller(), link), position.getMethod(), position.getBCI()); - } + this.position = position.addCaller(caller); } @Override @@ -65,4 +57,21 @@ graph().removeFixed(this); } } + + public void setPosition(BytecodePosition position) { + this.position = position; + } + + @Override + public boolean verify() { + BytecodePosition pos = position; + if (pos != null) { + // Verify that the outermost position belongs to this graph. + while (pos.getCaller() != null) { + pos = pos.getCaller(); + } + assert pos.getMethod().equals(graph().method()); + } + return super.verify(); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Thu May 28 17:44:05 2015 +0200 @@ -79,6 +79,30 @@ protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { GraphUtil.normalizeLoops(methodScope.graph); super.cleanupGraph(methodScope, start); + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (node instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) node; + if (mergeNode.forwardEndCount() == 1) { + methodScope.graph.reduceTrivialMerge(mergeNode); + } + } + } + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (node instanceof BeginNode || node instanceof KillingBeginNode) { + if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) { + GraphUtil.unlinkFixedNode((AbstractBeginNode) node); + node.safeDelete(); + } + } + } + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (!(node instanceof FixedNode) && node.hasNoUsages()) { + GraphUtil.killCFG(node); + } + } } @Override @@ -91,7 +115,7 @@ } @Override - protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { + protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { if (node instanceof IfNode) { IfNode ifNode = (IfNode) node; if (ifNode.condition() instanceof LogicNegationNode) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Thu May 28 17:44:05 2015 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; /** * The start node of a graph. diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu May 28 17:44:05 2015 +0200 @@ -24,6 +24,7 @@ import java.util.*; import java.util.concurrent.atomic.*; +import java.util.function.*; import com.oracle.graal.api.meta.Assumptions.Assumption; import com.oracle.graal.api.meta.*; @@ -115,9 +116,10 @@ private final Assumptions assumptions; /** - * The methods that were inlined while constructing this graph. + * Records the methods that were inlined while constructing this graph along with how many times + * each method was inlined. */ - private Set inlinedMethods = new HashSet<>(); + private Map inlinedMethods = new HashMap<>(); /** * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() @@ -217,17 +219,17 @@ this.start = start; } + /** + * Creates a copy of this graph. + * + * @param newName the name of the copy, used for debugging purposes (can be null) + * @param duplicationMapCallback consumer of the duplication map created during the copying + */ @Override - public StructuredGraph copy() { - return copy(name); - } - - public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod) { - return copy(newName, newMethod, AllowAssumptions.from(assumptions != null), isInlinedMethodRecordingEnabled()); - } - - public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod, AllowAssumptions allowAssumptions, boolean enableInlinedMethodRecording) { - StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, allowAssumptions); + protected Graph copy(String newName, Consumer> duplicationMapCallback) { + AllowAssumptions allowAssumptions = AllowAssumptions.from(assumptions != null); + boolean enableInlinedMethodRecording = isInlinedMethodRecordingEnabled(); + StructuredGraph copy = new StructuredGraph(newName, method, graphId, entryBCI, allowAssumptions); if (allowAssumptions == AllowAssumptions.YES && assumptions != null) { copy.assumptions.record(assumptions); } @@ -239,15 +241,13 @@ copy.hasValueProxies = hasValueProxies; Map replacements = Node.newMap(); replacements.put(start, copy.start); - copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements); + Map duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements); + if (duplicationMapCallback != null) { + duplicationMapCallback.accept(duplicates); + } return copy; } - @Override - public StructuredGraph copy(String newName) { - return copy(newName, method); - } - public ParameterNode getParameter(int index) { for (ParameterNode param : getNodes(ParameterNode.TYPE)) { if (param.index() == index) { @@ -516,12 +516,12 @@ } /** - * Disables recording of methods inlined while constructing this graph. This can be done at most + * Disables method inlining recording while constructing this graph. This can be done at most * once and must be done before any inlined methods are recorded. */ public void disableInlinedMethodRecording() { - assert inlinedMethods != null : "cannot disable inlined method recording more than once"; - assert inlinedMethods.isEmpty() : "cannot disable inlined method recording once methods have been recorded"; + assert inlinedMethods != null : "cannot disable method inlining recording more than once"; + assert inlinedMethods.isEmpty() : "cannot disable method inlining recording once methods have been recorded"; inlinedMethods = null; } @@ -532,11 +532,69 @@ /** * Gets the methods that were inlined while constructing this graph. * - * @return {@code null} if inlined method recording has been + * @return {@code null} if method inlining recording has been * {@linkplain #disableInlinedMethodRecording() disabled} */ public Set getInlinedMethods() { - return inlinedMethods; + return inlinedMethods == null ? null : inlinedMethods.keySet(); + } + + /** + * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording() + * disabled}, records that {@code inlinedMethod} was inlined to this graph. Otherwise, this + * method does nothing. + */ + public void recordInlinedMethod(ResolvedJavaMethod inlinedMethod) { + if (inlinedMethods != null) { + Integer count = inlinedMethods.get(inlinedMethod); + if (count != null) { + inlinedMethods.put(inlinedMethod, count + 1); + } else { + inlinedMethods.put(inlinedMethod, 1); + } + } + } + + /** + * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording() + * disabled}, updates the {@linkplain #getInlinedMethods() inlined methods} of this graph with + * the inlined methods of another graph. Otherwise, this method does nothing. + */ + public void updateInlinedMethods(StructuredGraph other) { + if (inlinedMethods != null) { + assert this != other; + Map otherInlinedMethods = other.inlinedMethods; + if (otherInlinedMethods != null) { + for (Map.Entry e : otherInlinedMethods.entrySet()) { + ResolvedJavaMethod key = e.getKey(); + Integer count = inlinedMethods.get(key); + if (count != null) { + inlinedMethods.put(key, count + e.getValue()); + } else { + inlinedMethods.put(key, e.getValue()); + } + } + } + } + } + + /** + * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this + * graph is constructed. This ignores how many bytecodes in each constituent method are actually + * parsed (which may be none for methods whose IR is retrieved from a cache or less than the + * full amount for any given method due to profile guided branch pruning). If method inlining + * recording has been {@linkplain #disableInlinedMethodRecording() disabled} for this graph, + * bytecode counts for inlined methods are not included in the returned value. + */ + public int getBytecodeSize() { + int res = method.getCodeSize(); + if (inlinedMethods != null) { + for (Map.Entry e : inlinedMethods.entrySet()) { + int inlinedBytes = e.getValue() * e.getKey().getCodeSize(); + res += inlinedBytes; + } + } + return res; } /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -27,7 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; public class ValueNodeUtil { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Thu May 28 17:44:05 2015 +0200 @@ -59,6 +59,10 @@ @Override public boolean inferStamp() { - return updateStamp(StampTool.meet(values())); + Stamp valuesStamp = StampTool.meet(values()); + if (stamp.isCompatible(valuesStamp)) { + valuesStamp = stamp.join(valuesStamp); + } + return updateStamp(valuesStamp); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,11 +31,15 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "/") -public final class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(IntegerDivNode.class); public IntegerDivNode(ValueNode x, ValueNode y) { - super(TYPE, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y); + this(TYPE, x, y); + } + + protected IntegerDivNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y); } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Thu May 28 17:44:05 2015 +0200 @@ -92,6 +92,8 @@ return new FloatEqualsNode(newX, newY); } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) { return new IntegerEqualsNode(newX, newY); + } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) { + return new IntegerEqualsNode(newX, newY); } throw GraalInternalError.shouldNotReachHere(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,11 +31,15 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "%") -public final class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(IntegerRemNode.class); public IntegerRemNode(ValueNode x, ValueNode y) { - super(TYPE, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y); + this(TYPE, x, y); + } + + protected IntegerRemNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y); } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowableArithmeticNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -28,4 +28,14 @@ * result. */ public interface NarrowableArithmeticNode { + + /** + * Check whether this operation can be narrowed to {@code resultBits} bit without loss of + * precision. + * + * @param resultBits + */ + default boolean isNarrowable(int resultBits) { + return true; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java Thu May 28 17:44:05 2015 +0200 @@ -37,7 +37,7 @@ import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "|") -public final class OrNode extends BinaryArithmeticNode implements BinaryCommutative { +public final class OrNode extends BinaryArithmeticNode implements BinaryCommutative, NarrowableArithmeticNode { public static final NodeClass TYPE = NodeClass.create(OrNode.class); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java Thu May 28 17:44:05 2015 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shr; import com.oracle.graal.graph.*; @@ -98,4 +99,19 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitShr(builder.operand(getX()), builder.operand(getY()))); } + + @Override + public boolean isNarrowable(int resultBits) { + if (super.isNarrowable(resultBits)) { + /* + * For signed right shifts, the narrow can be done before the shift if the cut off bits + * are all equal to the sign bit of the input. That's equivalent to the condition that + * the input is in the signed range of the narrow type. + */ + IntegerStamp inputStamp = (IntegerStamp) getX().stamp(); + return CodeUtil.minValue(resultBits) <= inputStamp.lowerBound() && inputStamp.upperBound() <= CodeUtil.maxValue(resultBits); + } else { + return false; + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java Thu May 28 17:44:05 2015 +0200 @@ -25,6 +25,7 @@ import java.io.*; import java.util.function.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp; @@ -38,7 +39,7 @@ * The {@code ShiftOp} class represents shift operations. */ @NodeInfo -public abstract class ShiftNode extends BinaryNode implements ArithmeticLIRLowerable { +public abstract class ShiftNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode { @SuppressWarnings("rawtypes") public static final NodeClass TYPE = NodeClass.create(ShiftNode.class); @@ -82,4 +83,18 @@ return getOp(getX()).getShiftAmountMask(stamp()); } + public boolean isNarrowable(int resultBits) { + assert CodeUtil.isPowerOf2(resultBits); + int narrowMask = resultBits - 1; + int wideMask = getShiftAmountMask(); + assert (wideMask & narrowMask) == narrowMask : String.format("wideMask %x should be wider than narrowMask %x", wideMask, narrowMask); + + /* + * Shifts are special because narrowing them also changes the implicit mask of the shift + * amount. We can narrow only if (y & wideMask) == (y & narrowMask) for all possible values + * of y. + */ + IntegerStamp yStamp = (IntegerStamp) getY().stamp(); + return (yStamp.upMask() & (wideMask & ~narrowMask)) == 0; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java Thu May 28 17:44:05 2015 +0200 @@ -34,7 +34,7 @@ * Square root. */ @NodeInfo -public final class SqrtNode extends UnaryArithmeticNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode { +public final class SqrtNode extends UnaryArithmeticNode implements ArithmeticLIRLowerable { public static final NodeClass TYPE = NodeClass.create(SqrtNode.class); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,12 +31,16 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "|/|") -public final class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(UnsignedDivNode.class); public UnsignedDivNode(ValueNode x, ValueNode y) { - super(TYPE, x.stamp().unrestricted(), x, y); + this(TYPE, x, y); + } + + protected UnsignedDivNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, x.stamp().unrestricted(), x, y); } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Thu May 28 17:44:05 2015 +0200 @@ -31,12 +31,16 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "|%|") -public final class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(UnsignedRemNode.class); public UnsignedRemNode(ValueNode x, ValueNode y) { - super(TYPE, x.stamp().unrestricted(), x, y); + this(TYPE, x, y); + } + + protected UnsignedRemNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, x.stamp().unrestricted(), x, y); } @Override diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java Thu May 28 17:44:05 2015 +0200 @@ -87,4 +87,18 @@ public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) { builder.setResult(this, gen.emitUShr(builder.operand(getX()), builder.operand(getY()))); } + + @Override + public boolean isNarrowable(int resultBits) { + if (super.isNarrowable(resultBits)) { + /* + * For unsigned right shifts, the narrow can be done before the shift if the cut off + * bits are all zero. + */ + IntegerStamp inputStamp = (IntegerStamp) getX().stamp(); + return (inputStamp.upMask() & ~(resultBits - 1)) == 0; + } else { + return false; + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java Thu May 28 17:44:05 2015 +0200 @@ -37,7 +37,7 @@ import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "^") -public final class XorNode extends BinaryArithmeticNode implements BinaryCommutative { +public final class XorNode extends BinaryArithmeticNode implements BinaryCommutative, NarrowableArithmeticNode { public static final NodeClass TYPE = NodeClass.create(XorNode.class); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -28,7 +28,7 @@ import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; public final class Block extends AbstractBlockBase { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -305,20 +305,52 @@ } } - private static void computeLoopBlocks(Block block, Loop loop) { - if (block.getLoop() == loop) { - return; - } - assert block.loop == loop.getParent(); - block.loop = loop; + private static void computeLoopBlocks(Block ablock, Loop aloop) { + final int process = 0; + final int stepOut = 1; + class Frame { + final Iterator blocks; + final Loop loop; + final Frame parent; - assert !loop.getBlocks().contains(block); - loop.getBlocks().add(block); + public Frame(Iterator blocks, Loop loop, Frame parent) { + this.blocks = blocks; + this.loop = loop; + this.parent = parent; + } + } + int state = process; + Frame c = new Frame(Arrays.asList(ablock).iterator(), aloop, null); + while (c != null) { + int nextState = state; + if (state == process) { + Loop loop = c.loop; + Block block = c.blocks.next(); + if (block.getLoop() == loop) { + nextState = stepOut; + } else { + assert block.loop == loop.getParent(); + block.loop = c.loop; - if (block != loop.getHeader()) { - for (Block pred : block.getPredecessors()) { - computeLoopBlocks(pred, loop); + assert !c.loop.getBlocks().contains(block); + c.loop.getBlocks().add(block); + + if (block != c.loop.getHeader()) { + c = new Frame(block.getPredecessors().iterator(), loop, c); + } else { + nextState = stepOut; + } + } + } else if (state == stepOut) { + if (c.blocks.hasNext()) { + nextState = process; + } else { + c = c.parent; + } + } else { + GraalInternalError.shouldNotReachHere(); } + state = nextState; } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; - -@NodeInfo(allowedUsageTypes = {InputType.Memory}) -public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode { - - public static final NodeClass TYPE = NodeClass.create(AbstractWriteNode.class); - @Input ValueNode value; - @OptionalInput(InputType.State) FrameState stateAfter; - @OptionalInput(InputType.Memory) Node lastLocationAccess; - - protected final boolean initialization; - - public FrameState stateAfter() { - return stateAfter; - } - - public void setStateAfter(FrameState x) { - assert x == null || x.isAlive() : "frame state must be in a graph"; - updateUsages(stateAfter, x); - stateAfter = x; - } - - public boolean hasSideEffect() { - return true; - } - - public ValueNode value() { - return value; - } - - /** - * Returns whether this write is the initialization of the written location. If it is true, the - * old value of the memory location is either uninitialized or zero. If it is false, the memory - * location is guaranteed to contain a valid value or zero. - */ - public boolean isInitialization() { - return initialization; - } - - protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) { - this(c, object, value, location, barrierType, false); - } - - protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) { - super(c, object, location, StampFactory.forVoid(), barrierType); - this.value = value; - this.initialization = initialization; - } - - protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) { - super(c, object, location, StampFactory.forVoid(), guard, barrierType, false, null); - this.value = value; - this.initialization = initialization; - } - - @Override - public boolean isAllowedUsageType(InputType type) { - return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type); - } - - @Override - public LocationIdentity getLocationIdentity() { - return location().getLocationIdentity(); - } - - public MemoryNode getLastLocationAccess() { - return (MemoryNode) lastLocationAccess; - } - - public void setLastLocationAccess(MemoryNode lla) { - Node newLla = ValueNodeUtil.asNode(lla); - updateUsages(lastLocationAccess, newLla); - lastLocationAccess = newLla; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +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.nodes.extended; - -import com.oracle.graal.nodes.*; - -public interface Access extends GuardedNode, HeapAccess { - - ValueNode object(); - - LocationNode accessLocation(); - - boolean canNullCheck(); - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; /** * Base class for nodes that modify a range of an array. diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -27,6 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; - -/** - * Accesses a value at an memory address specified by an {@linkplain #object object} and a - * {@linkplain #accessLocation() location}. The access does not include a null check on the object. - */ -@NodeInfo -public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access { - public static final NodeClass TYPE = NodeClass.create(FixedAccessNode.class); - - @OptionalInput(InputType.Guard) protected GuardingNode guard; - @Input protected ValueNode object; - @Input(InputType.Association) protected ValueNode location; - protected boolean nullCheck; - protected BarrierType barrierType; - - public ValueNode object() { - return object; - } - - protected void setObject(ValueNode x) { - updateUsages(object, x); - object = x; - } - - public LocationNode location() { - return (LocationNode) location; - } - - public LocationNode accessLocation() { - return (LocationNode) location; - } - - public boolean getNullCheck() { - return nullCheck; - } - - public void setNullCheck(boolean check) { - this.nullCheck = check; - } - - protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp) { - this(c, object, location, stamp, BarrierType.NONE); - } - - protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) { - this(c, object, location, stamp, null, barrierType, false, null); - } - - protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, - FrameState stateBefore) { - super(c, stamp, stateBefore); - this.object = object; - this.location = location; - this.guard = guard; - this.barrierType = barrierType; - this.nullCheck = nullCheck; - } - - @Override - public boolean canDeoptimize() { - return nullCheck; - } - - @Override - public GuardingNode getGuard() { - return guard; - } - - @Override - public void setGuard(GuardingNode guard) { - updateUsagesInterface(this.guard, guard); - this.guard = guard; - } - - @Override - public BarrierType getBarrierType() { - return barrierType; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.nodes.extended; - -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; - -/** - * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}. - */ -@NodeInfo -public abstract class FloatableAccessNode extends FixedAccessNode { - public static final NodeClass TYPE = NodeClass.create(FloatableAccessNode.class); - - protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp) { - super(c, object, location, stamp); - } - - protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { - super(c, object, location, stamp, guard, barrierType, false, null); - } - - protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, - FrameState stateBefore) { - super(c, object, location, stamp, guard, barrierType, nullCheck, stateBefore); - } - - public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess); - - protected boolean forceFixed; - - public void setForceFixed(boolean flag) { - this.forceFixed = flag; - } - - /** - * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in - * case G1 is enabled any access (read) to the java.lang.ref.Reference.referent field which has - * an attached write barrier with pre-semantics can not also float. - */ - public boolean canFloat() { - return !forceFixed && location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2011, 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.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; - -@NodeInfo -public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess { - public static final NodeClass TYPE = NodeClass.create(FloatingAccessNode.class); - - @Input ValueNode object; - @Input(InputType.Association) LocationNode location; - protected BarrierType barrierType; - - public ValueNode object() { - return object; - } - - public LocationNode location() { - return location; - } - - public LocationNode accessLocation() { - return location; - } - - public LocationIdentity getLocationIdentity() { - return location.getLocationIdentity(); - } - - protected FloatingAccessNode(NodeClass c, ValueNode object, LocationNode location, Stamp stamp) { - super(c, stamp); - this.object = object; - this.location = location; - } - - protected FloatingAccessNode(NodeClass c, ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { - super(c, stamp, guard); - this.object = object; - this.location = location; - this.barrierType = barrierType; - } - - @Override - public BarrierType getBarrierType() { - return barrierType; - } - - public boolean canNullCheck() { - return true; - } - - public abstract FixedAccessNode asFixedNode(); -} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A floating read of a value from memory specified in terms of an object base and an object - * relative location. This node does not null check the object. - */ -@NodeInfo -public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable { - public static final NodeClass TYPE = NodeClass.create(FloatingReadNode.class); - - @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; - - public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) { - this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE); - } - - public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) { - this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE); - } - - public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) { - super(TYPE, object, location, stamp, guard, barrierType); - this.lastLocationAccess = lastLocationAccess; - } - - public MemoryNode getLastLocationAccess() { - return lastLocationAccess; - } - - public void setLastLocationAccess(MemoryNode newlla) { - updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla)); - lastLocationAccess = newlla; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); - LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp()); - gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null)); - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { - return new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType()); - } - return ReadNode.canonicalizeRead(this, location(), object(), tool); - } - - @Override - public FixedAccessNode asFixedNode() { - return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType())); - } - - @Override - public boolean verify() { - MemoryNode lla = getLastLocationAccess(); - assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity(); - return super.verify(); - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** @@ -47,10 +48,7 @@ protected int bci = BytecodeFrame.UNKNOWN_BCI; public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { - super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); - this.arguments = new NodeInputList<>(this, arguments); - this.descriptor = descriptor; - this.foreignCalls = foreignCalls; + this(TYPE, foreignCalls, descriptor, arguments); } public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List arguments) { @@ -67,9 +65,9 @@ this.foreignCalls = foreignCalls; } - protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { - super(c, stamp); - this.arguments = new NodeInputList<>(this); + protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(c, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); + this.arguments = new NodeInputList<>(this, arguments); this.descriptor = descriptor; this.foreignCalls = foreignCalls; } @@ -107,6 +105,12 @@ } @Override + public void setStateAfter(FrameState x) { + assert hasSideEffect() || x == null; + super.setStateAfter(x); + } + + @Override public FrameState stateDuring() { return stateDuring; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Thu May 28 17:44:05 2015 +0200 @@ -65,7 +65,7 @@ @Override public void lower(LoweringTool tool) { - if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) { + if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) { return; } tool.getLowerer().lower(this, tool); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Thu May 28 17:44:05 2015 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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.nodes.extended; - -import com.oracle.graal.api.meta.*; - -/** - * This interface marks nodes that access some memory location, and that have an edge to the last - * node that kills this location. - */ -public interface MemoryAccess { - - LocationIdentity getLocationIdentity(); - - MemoryNode getLastLocationAccess(); - - /** - * @param lla the {@link MemoryNode} that represents the last kill of the location - */ - void setLastLocationAccess(MemoryNode lla); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAnchorNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodeinfo.StructuralInput.Memory; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -@NodeInfo(allowedUsageTypes = {InputType.Memory}) -public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable { - - public static final NodeClass TYPE = NodeClass.create(MemoryAnchorNode.class); - - public MemoryAnchorNode() { - super(TYPE, StampFactory.forVoid()); - } - - public void generate(NodeLIRBuilderTool generator) { - // Nothing to emit, since this node is used for structural purposes only. - } - - @Override - public Node canonical(CanonicalizerTool tool) { - return tool.allUsagesAvailable() && hasNoUsages() ? null : this; - } - - @NodeIntrinsic - public static native Memory anchor(); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -/** - * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations - * represented by location identities (i.e. change a value at one or more locations that belong to - * these location identities). - */ -public interface MemoryCheckpoint extends MemoryNode { - - FixedNode asNode(); - - interface Single extends MemoryCheckpoint { - - /** - * This method is used to determine which memory location is killed by this node. Returning - * the special value {@link LocationIdentity#any()} will kill all memory locations. - * - * @return the identity of the location killed by this node. - */ - LocationIdentity getLocationIdentity(); - - } - - interface Multi extends MemoryCheckpoint { - - /** - * This method is used to determine which set of memory locations is killed by this node. - * Returning the special value {@link LocationIdentity#any()} will kill all memory - * locations. - * - * @return the identities of all locations killed by this node. - */ - LocationIdentity[] getLocationIdentities(); - - } - - public class TypeAssertion { - - public static boolean correctType(Node node) { - return !(node instanceof MemoryCheckpoint) || (node instanceof MemoryCheckpoint.Single ^ node instanceof MemoryCheckpoint.Multi); - } - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +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.nodes.extended; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -/** - * This interface marks nodes that are part of the memory graph. - */ -public interface MemoryNode extends NodeInterface { - - ValueNode asNode(); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorExit.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.nodes.memory.*; + /** * Denotes monitor unlocking transition. */ diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -/** - * Reads an {@linkplain FixedAccessNode accessed} value. - */ -@NodeInfo -public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode { - - public static final NodeClass TYPE = NodeClass.create(ReadNode.class); - - public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) { - super(TYPE, object, location, stamp, null, barrierType); - } - - public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { - super(TYPE, object, location, stamp, guard, barrierType); - } - - public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) { - super(TYPE, object, location, stamp, guard, barrierType, nullCheck, stateBefore); - } - - public ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) { - /* - * Used by node intrinsics. Really, you can trust me on that! Since the initial value for - * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared - * type LocationNode. - */ - super(TYPE, object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); - LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp()); - gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this))); - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (tool.allUsagesAvailable() && hasNoUsages()) { - if (getGuard() != null && !(getGuard() instanceof FixedNode)) { - // The guard is necessary even if the read goes away. - return new ValueAnchorNode((ValueNode) getGuard()); - } else { - // Read without usages or guard can be safely removed. - return null; - } - } - if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { - return new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore()); - } - if (!getNullCheck()) { - return canonicalizeRead(this, location(), object(), tool); - } else { - // if this read is a null check, then replacing it with the value is incorrect for - // guard-type usages - return this; - } - } - - @Override - public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) { - return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType())); - } - - @Override - public boolean isAllowedUsageType(InputType type) { - return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type); - } - - public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) { - MetaAccessProvider metaAccess = tool.getMetaAccess(); - if (tool.canonicalizeReads()) { - if (metaAccess != null && object != null && object.isConstant() && !object.isNullConstant()) { - if ((location.getLocationIdentity().isImmutable()) && location instanceof ConstantLocationNode) { - long displacement = ((ConstantLocationNode) location).getDisplacement(); - Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement); - if (constant != null) { - return ConstantNode.forConstant(read.stamp(), constant, metaAccess); - } - } - } - if (location.getLocationIdentity().equals(LocationIdentity.ARRAY_LENGTH_LOCATION)) { - ValueNode length = GraphUtil.arrayLength(object); - if (length != null) { - // TODO Does this need a PiCastNode to the positive range? - return length; - } - } - } - return read; - } - - @Override - public boolean push(PiNode parent) { - if (!(location() instanceof ConstantLocationNode && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) { - return false; - } - - ObjectStamp piStamp = (ObjectStamp) parent.stamp(); - ResolvedJavaType receiverType = piStamp.type(); - if (receiverType == null) { - return false; - } - ConstantLocationNode constantLocationNode = (ConstantLocationNode) location(); - ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantLocationNode.getDisplacement(), constantLocationNode.getKind()); - if (field == null) { - // field was not declared by receiverType - return false; - } - - ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp(); - ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp); - if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) { - if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) { - replaceFirstInput(parent, parent.object()); - return true; - } - } - - return false; - } - - @Override - public void virtualize(VirtualizerTool tool) { - throw GraalInternalError.shouldNotReachHere("unexpected ReadNode before PEA"); - } - - public boolean canNullCheck() { - return true; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.LocationNode.Location; -import com.oracle.graal.nodes.spi.*; - -/** - * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}. - */ -@NodeInfo -public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable { - - public static final NodeClass TYPE = NodeClass.create(WriteNode.class); - - public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) { - super(TYPE, object, value, location, barrierType); - } - - public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) { - super(TYPE, object, value, location, barrierType, initialization); - } - - public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) { - super(TYPE, object, value, location, barrierType, guard, initialization); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); - LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp()); - gen.getLIRGeneratorTool().emitStore(writeKind, address, gen.operand(value()), gen.state(this)); - } - - @Override - public void simplify(SimplifierTool tool) { - if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { - setObject(((PiNode) object()).getOriginalNode()); - } - } - - @NodeIntrinsic - public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType); - - @Override - public void virtualize(VirtualizerTool tool) { - throw GraalInternalError.shouldNotReachHere("unexpected WriteNode before PEA"); - } - - public boolean canNullCheck() { - return true; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -27,7 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; /** * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release. diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -29,7 +29,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu May 28 17:44:05 2015 +0200 @@ -41,7 +41,7 @@ * Implements a type check against a compile-time known type. */ @NodeInfo -public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy { +public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy { public static final NodeClass TYPE = NodeClass.create(CheckCastNode.class); @Input protected ValueNode object; @@ -55,7 +55,11 @@ protected final boolean forStoreCheck; public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) { - super(TYPE, StampFactory.declaredTrusted(type)); + this(TYPE, type, object, profile, forStoreCheck); + } + + protected CheckCastNode(NodeClass c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) { + super(c, StampFactory.declaredTrusted(type)); assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp(); assert type != null; this.type = type; @@ -178,7 +182,7 @@ return this; } - private static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) { + protected static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) { ResolvedJavaType objectType = StampTool.typeOrNull(object); if (objectType != null && type.isAssignableFrom(objectType)) { // we don't have to check for null types here because they will also pass the diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -27,7 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -27,7 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Thu May 28 17:44:05 2015 +0200 @@ -36,14 +36,18 @@ * The {@code InstanceOfNode} represents an instanceof test. */ @NodeInfo -public final class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { +public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { public static final NodeClass TYPE = NodeClass.create(InstanceOfNode.class); protected final ResolvedJavaType type; protected JavaTypeProfile profile; public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { - super(TYPE, object); + this(TYPE, type, object, profile); + } + + protected InstanceOfNode(NodeClass c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { + super(c, object); this.type = type; this.profile = profile; assert type != null; @@ -128,7 +132,7 @@ return LogicConstantNode.contradiction(); } else { boolean superType = inputType.isAssignableFrom(type); - if (!superType && !isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)) { + if (!superType && (type.asExactType() != null || (!isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)))) { return LogicConstantNode.contradiction(); } // since the subtype comparison was only performed on a declared type we don't diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Thu May 28 17:44:05 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Thu May 28 17:44:05 2015 +0200 @@ -175,7 +175,7 @@ * interface methods calls. */ if (declaredReceiverType.isInterface()) { - tryCheckCastSingleImplementor(receiver, declaredReceiverType); + tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, declaredReceiverType); } if (receiver instanceof UncheckedInterfaceProvider) { @@ -184,14 +184,22 @@ if (uncheckedStamp != null) { ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp); if (uncheckedReceiverType.isInterface()) { - tryCheckCastSingleImplementor(receiver, uncheckedReceiverType); + tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, uncheckedReceiverType); } } } } } - private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) { + private void tryCheckCastSingleImplementor(Assumptions assumptions, ValueNode receiver, ResolvedJavaType declaredReceiverType) { + if (assumptions == null) { + /* + * Even though we are not registering an assumption (see comment below), the + * optimization is only valid when speculative optimizations are enabled. + */ + return; + } + ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor(); if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) { ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu May 28 17:44:05 2015 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu May 28 17:44:05 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu May 28 17:44:05 2015 +0200 @@ -37,13 +37,17 @@ * The {@code NewInstanceNode} represents the allocation of an instance class object. */ @NodeInfo(nameTemplate = "New {p#instanceClass/s}") -public final class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation { +public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation { public static final NodeClass TYPE = NodeClass.create(NewInstanceNode.class); protected final ResolvedJavaType instanceClass; public NewInstanceNode(ResolvedJavaType type, boolean fillContents) { - super(TYPE, StampFactory.exactNonNull(type), fillContents); + this(TYPE, type, fillContents); + } + + protected NewInstanceNode(NodeClass c, ResolvedJavaType type, boolean fillContents) { + super(c, StampFactory.exactNonNull(type), fillContents); assert !type.isArray() && !type.isInterface() && !type.isPrimitive(); this.instanceClass = type; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Thu May 28 17:44:05 2015 +0200 @@ -33,7 +33,7 @@ * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array. */ @NodeInfo -public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider { +public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider { public static final NodeClass TYPE = NodeClass.create(NewMultiArrayNode.class); @Input protected NodeInputList dimensions; @@ -52,7 +52,11 @@ } public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) { - super(TYPE, StampFactory.exactNonNull(type)); + this(TYPE, type, dimensions); + } + + protected NewMultiArrayNode(NodeClass c, ResolvedJavaType type, ValueNode[] dimensions) { + super(c, StampFactory.exactNonNull(type)); this.type = type; this.dimensions = new NodeInputList<>(this, dimensions); assert dimensions.length > 0 && type.isArray(); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Thu May 28 17:44:05 2015 +0200 @@ -68,10 +68,14 @@ ObjectStamp objectStamp = (ObjectStamp) object.stamp(); if (objectStamp.isExactType()) { return objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && assumptions != null) { + } else if (objectStamp.type() != null) { AssumptionResult result = objectStamp.type().hasFinalizableSubclass(); - assumptions.record(result); - return result.getResult(); + if (result.isAssumptionFree()) { + return result.getResult(); + } else if (assumptions != null) { + assumptions.record(result); + return result.getResult(); + } } return true; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Thu May 28 17:44:05 2015 +0200 @@ -166,7 +166,7 @@ if (objectType != null) { ResolvedJavaType instanceofType = type; if (instanceofType.equals(objectType)) { - if (objectStamp.nonNull()) { + if (objectStamp.nonNull() && (objectStamp.isExactType() || objectType.isFinal())) { return TriState.TRUE; } } else { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractMemoryCheckpoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractMemoryCheckpoint.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; + +/** + * Provides an implementation of {@link StateSplit}. + */ +@NodeInfo +public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint { + + public static final NodeClass TYPE = NodeClass.create(AbstractMemoryCheckpoint.class); + + protected AbstractMemoryCheckpoint(NodeClass c, Stamp stamp) { + this(c, stamp, null); + } + + protected AbstractMemoryCheckpoint(NodeClass c, Stamp stamp, FrameState stateAfter) { + super(c, stamp, stateAfter); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractWriteNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/AbstractWriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +@NodeInfo(allowedUsageTypes = {InputType.Memory}) +public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode { + + public static final NodeClass TYPE = NodeClass.create(AbstractWriteNode.class); + @Input ValueNode value; + @OptionalInput(InputType.State) FrameState stateAfter; + @OptionalInput(InputType.Memory) Node lastLocationAccess; + + protected final boolean initialization; + + public FrameState stateAfter() { + return stateAfter; + } + + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + updateUsages(stateAfter, x); + stateAfter = x; + } + + public boolean hasSideEffect() { + return true; + } + + public ValueNode value() { + return value; + } + + /** + * Returns whether this write is the initialization of the written location. If it is true, the + * old value of the memory location is either uninitialized or zero. If it is false, the memory + * location is guaranteed to contain a valid value or zero. + */ + public boolean isInitialization() { + return initialization; + } + + protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) { + this(c, object, value, location, barrierType, false); + } + + protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) { + super(c, object, location, StampFactory.forVoid(), barrierType); + this.value = value; + this.initialization = initialization; + } + + protected AbstractWriteNode(NodeClass c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) { + super(c, object, location, StampFactory.forVoid(), guard, barrierType, false, null); + this.value = value; + this.initialization = initialization; + } + + @Override + public boolean isAllowedUsageType(InputType type) { + return (type == InputType.Guard && getNullCheck()) ? true : super.isAllowedUsageType(type); + } + + @Override + public LocationIdentity getLocationIdentity() { + return location().getLocationIdentity(); + } + + public MemoryNode getLastLocationAccess() { + return (MemoryNode) lastLocationAccess; + } + + public void setLastLocationAccess(MemoryNode lla) { + Node newLla = ValueNodeUtil.asNode(lla); + updateUsages(lastLocationAccess, newLla); + lastLocationAccess = newLla; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/Access.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/Access.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 2015, 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.memory; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +public interface Access extends GuardedNode, HeapAccess { + + ValueNode object(); + + LocationNode accessLocation(); + + boolean canNullCheck(); + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FixedAccessNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FixedAccessNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +/** + * Accesses a value at an memory address specified by an {@linkplain #object object} and a + * {@linkplain #accessLocation() location}. The access does not include a null check on the object. + */ +@NodeInfo +public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access { + public static final NodeClass TYPE = NodeClass.create(FixedAccessNode.class); + + @OptionalInput(InputType.Guard) protected GuardingNode guard; + @Input protected ValueNode object; + @Input(InputType.Association) protected ValueNode location; + protected boolean nullCheck; + protected BarrierType barrierType; + + public ValueNode object() { + return object; + } + + protected void setObject(ValueNode x) { + updateUsages(object, x); + object = x; + } + + public LocationNode location() { + return (LocationNode) location; + } + + public LocationNode accessLocation() { + return (LocationNode) location; + } + + public boolean getNullCheck() { + return nullCheck; + } + + public void setNullCheck(boolean check) { + this.nullCheck = check; + } + + protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp) { + this(c, object, location, stamp, BarrierType.NONE); + } + + protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) { + this(c, object, location, stamp, null, barrierType, false, null); + } + + protected FixedAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, + FrameState stateBefore) { + super(c, stamp, stateBefore); + this.object = object; + this.location = location; + this.guard = guard; + this.barrierType = barrierType; + this.nullCheck = nullCheck; + } + + @Override + public boolean canDeoptimize() { + return nullCheck; + } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsagesInterface(this.guard, guard); + this.guard = guard; + } + + @Override + public BarrierType getBarrierType() { + return barrierType; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatableAccessNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatableAccessNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +/** + * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}. + */ +@NodeInfo +public abstract class FloatableAccessNode extends FixedAccessNode { + public static final NodeClass TYPE = NodeClass.create(FloatableAccessNode.class); + + protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp) { + super(c, object, location, stamp); + } + + protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { + super(c, object, location, stamp, guard, barrierType, false, null); + } + + protected FloatableAccessNode(NodeClass c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, + FrameState stateBefore) { + super(c, object, location, stamp, guard, barrierType, nullCheck, stateBefore); + } + + public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess); + + protected boolean forceFixed; + + public void setForceFixed(boolean flag) { + this.forceFixed = flag; + } + + /** + * AccessNodes can float only if their location identities are not ANY_LOCATION. Furthermore, in + * case G1 is enabled any access (read) to the java.lang.ref.Reference.referent field which has + * an attached write barrier with pre-semantics can not also float. + */ + public boolean canFloat() { + return !forceFixed && location().getLocationIdentity().isSingle() && getBarrierType() == BarrierType.NONE; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingAccessNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingAccessNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +@NodeInfo +public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess { + public static final NodeClass TYPE = NodeClass.create(FloatingAccessNode.class); + + @Input ValueNode object; + @Input(InputType.Association) LocationNode location; + protected BarrierType barrierType; + + public ValueNode object() { + return object; + } + + public LocationNode location() { + return location; + } + + public LocationNode accessLocation() { + return location; + } + + public LocationIdentity getLocationIdentity() { + return location.getLocationIdentity(); + } + + protected FloatingAccessNode(NodeClass c, ValueNode object, LocationNode location, Stamp stamp) { + super(c, stamp); + this.object = object; + this.location = location; + } + + protected FloatingAccessNode(NodeClass c, ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { + super(c, stamp, guard); + this.object = object; + this.location = location; + this.barrierType = barrierType; + } + + @Override + public BarrierType getBarrierType() { + return barrierType; + } + + public boolean canNullCheck() { + return true; + } + + public abstract FixedAccessNode asFixedNode(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingReadNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/FloatingReadNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A floating read of a value from memory specified in terms of an object base and an object + * relative location. This node does not null check the object. + */ +@NodeInfo +public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable { + public static final NodeClass TYPE = NodeClass.create(FloatingReadNode.class); + + @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess; + + public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp) { + this(object, location, lastLocationAccess, stamp, null, BarrierType.NONE); + } + + public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard) { + this(object, location, lastLocationAccess, stamp, guard, BarrierType.NONE); + } + + public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) { + super(TYPE, object, location, stamp, guard, barrierType); + this.lastLocationAccess = lastLocationAccess; + } + + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + public void setLastLocationAccess(MemoryNode newlla) { + updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(newlla)); + lastLocationAccess = newlla; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); + LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp()); + gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, null)); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + return new FloatingReadNode(((PiNode) object()).getOriginalNode(), location(), getLastLocationAccess(), stamp(), getGuard(), getBarrierType()); + } + return ReadNode.canonicalizeRead(this, location(), object(), tool); + } + + @Override + public FixedAccessNode asFixedNode() { + return graph().add(new ReadNode(object(), accessLocation(), stamp(), getGuard(), getBarrierType())); + } + + @Override + public boolean verify() { + MemoryNode lla = getLastLocationAccess(); + assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity(); + return super.verify(); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/HeapAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/HeapAccess.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +/** + * Encapsulates properties of a node describing how it accesses the heap. + */ +public interface HeapAccess { + + /** + * The types of (write/read) barriers attached to stores. + */ + public enum BarrierType { + /** + * Primitive stores which do not necessitate barriers. + */ + NONE, + /** + * Array object stores which necessitate precise barriers. + */ + PRECISE, + /** + * Field object stores which necessitate imprecise barriers. + */ + IMPRECISE + } + + /** + * Gets the write barrier type for that particular access. + */ + BarrierType getBarrierType(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAccess.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; + +/** + * This interface marks nodes that access some memory location, and that have an edge to the last + * node that kills this location. + */ +public interface MemoryAccess { + + LocationIdentity getLocationIdentity(); + + MemoryNode getLastLocationAccess(); + + /** + * @param lla the {@link MemoryNode} that represents the last kill of the location + */ + void setLastLocationAccess(MemoryNode lla); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAnchorNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryAnchorNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2015, 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.memory; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodeinfo.StructuralInput.Memory; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +@NodeInfo(allowedUsageTypes = {InputType.Memory}) +public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable { + + public static final NodeClass TYPE = NodeClass.create(MemoryAnchorNode.class); + + public MemoryAnchorNode() { + super(TYPE, StampFactory.forVoid()); + } + + public void generate(NodeLIRBuilderTool generator) { + // Nothing to emit, since this node is used for structural purposes only. + } + + @Override + public Node canonical(CanonicalizerTool tool) { + return tool.allUsagesAvailable() && hasNoUsages() ? null : this; + } + + @NodeIntrinsic + public static native Memory anchor(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryCheckpoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryCheckpoint.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +/** + * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations + * represented by location identities (i.e. change a value at one or more locations that belong to + * these location identities). + */ +public interface MemoryCheckpoint extends MemoryNode { + + FixedNode asNode(); + + interface Single extends MemoryCheckpoint { + + /** + * This method is used to determine which memory location is killed by this node. Returning + * the special value {@link LocationIdentity#any()} will kill all memory locations. + * + * @return the identity of the location killed by this node. + */ + LocationIdentity getLocationIdentity(); + + } + + interface Multi extends MemoryCheckpoint { + + /** + * This method is used to determine which set of memory locations is killed by this node. + * Returning the special value {@link LocationIdentity#any()} will kill all memory + * locations. + * + * @return the identities of all locations killed by this node. + */ + LocationIdentity[] getLocationIdentities(); + + } + + public class TypeAssertion { + + public static boolean correctType(Node node) { + return !(node instanceof MemoryCheckpoint) || (node instanceof MemoryCheckpoint.Single ^ node instanceof MemoryCheckpoint.Multi); + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMap.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +import java.util.*; + +import com.oracle.graal.api.meta.*; + +/** + * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the + * location. + */ +public interface MemoryMap { + + /** + * Gets the last node that that (potentially) wrote to {@code locationIdentity}. + */ + MemoryNode getLastLocationAccess(LocationIdentity locationIdentity); + + /** + * Gets the location identities in the domain of this map. + */ + Collection getLocations(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMapNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryMapNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014, 2015, 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.memory; + +import static com.oracle.graal.api.meta.LocationIdentity.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +@NodeInfo(allowedUsageTypes = {InputType.Extension, InputType.Memory}) +public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(MemoryMapNode.class); + protected final List locationIdentities; + @Input(InputType.Memory) NodeInputList nodes; + + private boolean checkOrder(Map mmap) { + for (int i = 0; i < locationIdentities.size(); i++) { + LocationIdentity locationIdentity = locationIdentities.get(i); + ValueNode n = nodes.get(i); + assertTrue(mmap.get(locationIdentity) == n, "iteration order of keys differs from values in input map"); + } + return true; + } + + public MemoryMapNode(Map mmap) { + super(TYPE, StampFactory.forVoid()); + locationIdentities = new ArrayList<>(mmap.keySet()); + nodes = new NodeInputList<>(this, mmap.values()); + assert checkOrder(mmap); + } + + public boolean isEmpty() { + if (locationIdentities.isEmpty()) { + return true; + } + if (locationIdentities.size() == 1) { + if (nodes.get(0) instanceof StartNode) { + return true; + } + } + return false; + } + + public MemoryNode getLastLocationAccess(LocationIdentity locationIdentity) { + if (locationIdentity.isImmutable()) { + return null; + } else { + int index = locationIdentities.indexOf(locationIdentity); + if (index == -1) { + index = locationIdentities.indexOf(any()); + } + assert index != -1; + return (MemoryNode) nodes.get(index); + } + } + + public Collection getLocations() { + return locationIdentities; + } + + public Map toMap() { + HashMap res = CollectionsFactory.newMap(locationIdentities.size()); + for (int i = 0; i < nodes.size(); i++) { + res.put(locationIdentities.get(i), (MemoryNode) nodes.get(i)); + } + return res; + } + + public void generate(NodeLIRBuilderTool generator) { + // nothing to do... + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 2015, 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.memory; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +/** + * This interface marks nodes that are part of the memory graph. + */ +public interface MemoryNode extends NodeInterface { + + ValueNode asNode(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryPhiNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/MemoryPhiNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; + +/** + * Memory {@code PhiNode}s merge memory dependencies at control flow merges. + */ +@NodeInfo(nameTemplate = "\u03D5({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) +public final class MemoryPhiNode extends PhiNode implements MemoryNode { + + public static final NodeClass TYPE = NodeClass.create(MemoryPhiNode.class); + @Input(InputType.Memory) NodeInputList values; + protected final LocationIdentity locationIdentity; + + public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) { + super(TYPE, StampFactory.forVoid(), merge); + this.locationIdentity = locationIdentity; + this.values = new NodeInputList<>(this); + } + + public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) { + super(TYPE, StampFactory.forVoid(), merge); + this.locationIdentity = locationIdentity; + this.values = new NodeInputList<>(this, values); + } + + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } + + @Override + public NodeInputList values() { + return values; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/ReadNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * Reads an {@linkplain FixedAccessNode accessed} value. + */ +@NodeInfo +public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode { + + public static final NodeClass TYPE = NodeClass.create(ReadNode.class); + + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) { + super(TYPE, object, location, stamp, null, barrierType); + } + + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) { + super(TYPE, object, location, stamp, guard, barrierType); + } + + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) { + super(TYPE, object, location, stamp, guard, barrierType, nullCheck, stateBefore); + } + + public ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) { + /* + * Used by node intrinsics. Really, you can trust me on that! Since the initial value for + * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared + * type LocationNode. + */ + super(TYPE, object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); + LIRKind readKind = gen.getLIRGeneratorTool().getLIRKind(stamp()); + gen.setResult(this, gen.getLIRGeneratorTool().emitLoad(readKind, address, gen.state(this))); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (tool.allUsagesAvailable() && hasNoUsages()) { + if (getGuard() != null && !(getGuard() instanceof FixedNode)) { + // The guard is necessary even if the read goes away. + return new ValueAnchorNode((ValueNode) getGuard()); + } else { + // Read without usages or guard can be safely removed. + return null; + } + } + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + return new ReadNode(((PiNode) object()).getOriginalNode(), location(), stamp(), getGuard(), getBarrierType(), getNullCheck(), stateBefore()); + } + if (!getNullCheck()) { + return canonicalizeRead(this, location(), object(), tool); + } else { + // if this read is a null check, then replacing it with the value is incorrect for + // guard-type usages + return this; + } + } + + @Override + public FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess) { + return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard(), getBarrierType())); + } + + @Override + public boolean isAllowedUsageType(InputType type) { + return (getNullCheck() && type == InputType.Guard) ? true : super.isAllowedUsageType(type); + } + + public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) { + MetaAccessProvider metaAccess = tool.getMetaAccess(); + if (tool.canonicalizeReads()) { + if (metaAccess != null && object != null && object.isConstant() && !object.isNullConstant() && location instanceof ConstantLocationNode) { + long displacement = ((ConstantLocationNode) location).getDisplacement(); + if ((location.getLocationIdentity().isImmutable())) { + Constant constant = read.stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), object.asConstant(), displacement); + if (constant != null) { + return ConstantNode.forConstant(read.stamp(), constant, metaAccess); + } + } + + Constant constant = tool.getConstantReflection().readConstantArrayElementForOffset(object.asJavaConstant(), displacement); + if (constant != null) { + return ConstantNode.forConstant(read.stamp(), constant, metaAccess); + } + } + if (location.getLocationIdentity().equals(LocationIdentity.ARRAY_LENGTH_LOCATION)) { + ValueNode length = GraphUtil.arrayLength(object); + if (length != null) { + // TODO Does this need a PiCastNode to the positive range? + return length; + } + } + } + return read; + } + + @Override + public boolean push(PiNode parent) { + if (!(location() instanceof ConstantLocationNode && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) { + return false; + } + + ObjectStamp piStamp = (ObjectStamp) parent.stamp(); + ResolvedJavaType receiverType = piStamp.type(); + if (receiverType == null) { + return false; + } + ConstantLocationNode constantLocationNode = (ConstantLocationNode) location(); + ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantLocationNode.getDisplacement(), constantLocationNode.getKind()); + if (field == null) { + // field was not declared by receiverType + return false; + } + + ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp(); + ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp); + if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) { + if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) { + replaceFirstInput(parent, parent.object()); + return true; + } + } + + return false; + } + + @Override + public void virtualize(VirtualizerTool tool) { + throw GraalInternalError.shouldNotReachHere("unexpected ReadNode before PEA"); + } + + public boolean canNullCheck() { + return true; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/memory/WriteNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011, 2015, 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.memory; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.Location; +import com.oracle.graal.nodes.spi.*; + +/** + * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}. + */ +@NodeInfo +public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(WriteNode.class); + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) { + super(TYPE, object, value, location, barrierType); + } + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) { + super(TYPE, object, value, location, barrierType, initialization); + } + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) { + super(TYPE, object, value, location, barrierType, guard, initialization); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + Value address = location().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(object())); + LIRKind writeKind = gen.getLIRGeneratorTool().getLIRKind(value().stamp()); + gen.getLIRGeneratorTool().emitStore(writeKind, address, gen.operand(value()), gen.state(this)); + } + + @Override + public void simplify(SimplifierTool tool) { + if (object() instanceof PiNode && ((PiNode) object()).getGuard() == getGuard()) { + setObject(((PiNode) object()).getOriginalNode()); + } + } + + @NodeIntrinsic + public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter BarrierType barrierType); + + @Override + public void virtualize(VirtualizerTool tool) { + throw GraalInternalError.shouldNotReachHere("unexpected WriteNode before PEA"); + } + + public boolean canNullCheck() { + return true; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryProxy.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -23,7 +23,7 @@ package com.oracle.graal.nodes.spi; import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; public interface MemoryProxy extends Proxy, MemoryNode { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Thu May 28 17:44:05 2015 +0200 @@ -123,11 +123,6 @@ Collection getAllReplacements(); /** - * Determines whether the replacement of this method is flagged as being inlined always. - */ - boolean isForcedSubstitution(ResolvedJavaMethod methodAt); - - /** * Register snippet templates. */ void registerSnippetTemplateCache(SnippetTemplateCache snippetTemplates); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Thu May 28 17:44:05 2015 +0200 @@ -33,14 +33,18 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") -public final class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { +public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { public static final NodeClass TYPE = NodeClass.create(VirtualArrayNode.class); protected final ResolvedJavaType componentType; protected final int length; public VirtualArrayNode(ResolvedJavaType componentType, int length) { - super(TYPE, componentType.getArrayClass(), true); + this(TYPE, componentType, length); + } + + protected VirtualArrayNode(NodeClass c, ResolvedJavaType componentType, int length) { + super(c, componentType.getArrayClass(), true); this.componentType = componentType; this.length = length; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java --- a/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/GraalJars.java Thu May 28 17:44:05 2015 +0200 @@ -1,10 +1,3 @@ -package com.oracle.graal.options.processor; - -import java.io.*; -import java.util.*; -import java.util.stream.*; -import java.util.zip.*; - /* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,6 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.oracle.graal.options.processor; + +import java.io.*; +import java.util.*; +import java.util.stream.*; +import java.util.zip.*; + public class GraalJars implements Iterable { private final List jars = new ArrayList<>(2); @@ -60,4 +60,4 @@ } return null; } -} \ No newline at end of file +} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Thu May 28 17:44:05 2015 +0200 @@ -134,9 +134,6 @@ } private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph) { - if (!deoptAction.doesInvalidateCompilation()) { - return; - } if (deoptBegin instanceof AbstractMergeNode) { AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin; Debug.log("Visiting %s", mergeNode); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu May 28 17:44:05 2015 +0200 @@ -36,6 +36,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.util.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -36,6 +36,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Thu May 28 17:44:05 2015 +0200 @@ -53,12 +53,6 @@ public class InliningUtil { private static final String inliningDecisionsScopeString = "InliningDecisions"; - /** - * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level - * and all inlined methods), irrespective of how many bytecodes in each method are actually - * parsed (which may be none for methods whose IR is retrieved from a cache). - */ - public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes"); /** * Print a HotSpot-style inlining message to the console. @@ -321,7 +315,7 @@ unwindNode = (UnwindNode) duplicates.get(unwindNode); } - finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph.getInlinedMethods(), canonicalizedNodes); + finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes); GraphUtil.killCFG(invokeNode); @@ -329,7 +323,7 @@ } public static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions, - Set inlinedMethods, List canonicalizedNodes) { + StructuredGraph inlineGraph, List canonicalizedNodes) { FixedNode invokeNode = invoke.asNode(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); @@ -401,9 +395,7 @@ } // Copy inlined methods from inlinee to caller - if (inlinedMethods != null && graph.getInlinedMethods() != null) { - graph.getInlinedMethods().addAll(inlinedMethods); - } + graph.updateInlinedMethods(inlineGraph); return returnValue; } @@ -427,11 +419,18 @@ } public static BytecodePosition processSimpleInfopoint(Invoke invoke, SimpleInfopointNode infopointNode, BytecodePosition incomingPos) { - BytecodePosition pos = incomingPos != null ? incomingPos : new BytecodePosition(toBytecodePosition(invoke.stateAfter().outerFrameState()), invoke.asNode().graph().method(), invoke.bci()); + BytecodePosition pos = processBytecodePosition(invoke, incomingPos); infopointNode.addCaller(pos); + assert infopointNode.verify(); return pos; } + public static BytecodePosition processBytecodePosition(Invoke invoke, BytecodePosition incomingPos) { + assert invoke.stateAfter() != null; + assert incomingPos == null || incomingPos.equals(InliningUtil.processBytecodePosition(invoke, null)) : incomingPos + " " + InliningUtil.processBytecodePosition(invoke, null); + return incomingPos != null ? incomingPos : new BytecodePosition(FrameState.toBytecodePosition(invoke.stateAfter().outerFrameState()), invoke.stateAfter().method(), invoke.bci()); + } + public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) { if (stateAfter != null) { int callerLockDepth = stateAfter.nestedLockDepth(); @@ -439,13 +438,6 @@ } } - private static BytecodePosition toBytecodePosition(FrameState fs) { - if (fs == null) { - return null; - } - return new BytecodePosition(toBytecodePosition(fs.outerFrameState()), fs.method(), fs.bci); - } - protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map duplicates, FrameState stateAtExceptionEdge, boolean alwaysDuplicateStateAfter) { FrameState stateAtReturn = invoke.stateAfter(); FrameState outerFrameState = null; @@ -468,14 +460,28 @@ Kind invokeReturnKind = invoke.asNode().getKind(); if (frameState.bci == BytecodeFrame.AFTER_BCI) { + FrameState stateAfterReturn = stateAtReturn; + if (frameState.method() == null) { + // This is a frame state for a side effect within an intrinsic + // that was parsed for post-parse intrinsification + for (Node usage : frameState.usages()) { + if (usage instanceof ForeignCallNode) { + // A foreign call inside an intrinsic needs to have + // the BCI of the invoke being intrinsified + ForeignCallNode foreign = (ForeignCallNode) usage; + foreign.setBci(invoke.bci()); + } + } + } + /* * pop return kind from invoke's stateAfter and replace with this frameState's return * value (top of stack) */ - FrameState stateAfterReturn = stateAtReturn; - if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || (frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)))) { + if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) { stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0)); } + frameState.replaceAndDelete(stateAfterReturn); return stateAfterReturn; } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) { @@ -527,8 +533,11 @@ // in the intrinsic code. assert inlinedMethod.getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + frameState; + } else if (frameState.method().getName().equals(inlinedMethod.getName())) { + // This can happen for method substitutions. } else { - throw new AssertionError(frameState.toString()); + throw new AssertionError(String.format("inlinedMethod=%s frameState.method=%s frameState=%s invoke.method=%s", inlinedMethod, frameState.method(), frameState, + invoke.callTarget().targetMethod())); } } return true; @@ -581,25 +590,26 @@ ValueNode singleReturnValue = null; PhiNode returnValuePhi = null; for (ReturnNode returnNode : returnNodes) { - if (returnNode.result() != null) { - if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == returnNode.result())) { + ValueNode result = returnNode.result(); + if (result != null) { + if (returnValuePhi == null && (singleReturnValue == null || singleReturnValue == result)) { /* Only one return value, so no need yet for a phi node. */ - singleReturnValue = returnNode.result(); + singleReturnValue = result; } else if (returnValuePhi == null) { /* Found a second return value, so create phi node. */ - returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge)); + returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(result.stamp().unrestricted(), merge)); if (canonicalizedNodes != null) { canonicalizedNodes.add(returnValuePhi); } for (int i = 0; i < merge.forwardEndCount(); i++) { returnValuePhi.addInput(singleReturnValue); } - returnValuePhi.addInput(returnNode.result()); + returnValuePhi.addInput(result); } else { /* Multiple return values, just add to existing phi node. */ - returnValuePhi.addInput(returnNode.result()); + returnValuePhi.addInput(result); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java Thu May 28 17:44:05 2015 +0200 @@ -57,11 +57,8 @@ Map duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes); getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap); - InliningUtil.InlinedBytecodes.add(concrete.getCodeSize()); StructuredGraph graph = invoke.asNode().graph(); - if (graph.isInlinedMethodRecordingEnabled()) { - graph.getInlinedMethods().add(concrete); - } + graph.recordInlinedMethod(concrete); return canonicalizeNodes; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Thu May 28 17:44:05 2015 +0200 @@ -61,7 +61,7 @@ public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) { StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci()); // TODO copying the graph is only necessary if it is modified or if it contains any invokes - this.graph = original.copy(); + this.graph = (StructuredGraph) original.copy(); specializeGraphToArguments(invoke, context, canonicalizer); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Thu May 28 17:44:05 2015 +0200 @@ -78,9 +78,6 @@ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) { return false; } - if (!replacements.isForcedSubstitution(info.methodAt(i))) { - return false; - } } return true; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Thu May 28 17:44:05 2015 +0200 @@ -117,7 +117,7 @@ return "it is an abstract method"; } else if (!method.getDeclaringClass().isInitialized()) { return "the method's class is not initialized"; - } else if (!method.canBeInlined() && !context.getReplacements().isForcedSubstitution(method)) { + } else if (!method.canBeInlined()) { return "it is marked non-inlinable"; } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) { return "it exceeds the maximum recursive inlining depth"; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java Thu May 28 17:44:05 2015 +0200 @@ -70,6 +70,31 @@ return false; } + /** + * Removes the first instance of the given phase class, looking recursively into inner phase + * suites. + */ + public boolean removePhase(Class> phaseClass) { + ListIterator> it = phases.listIterator(); + while (it.hasNext()) { + BasePhase phase = it.next(); + if (phaseClass.isInstance(phase)) { + it.remove(); + return true; + } else if (phase instanceof PhaseSuite) { + @SuppressWarnings("unchecked") + PhaseSuite innerSuite = (PhaseSuite) phase; + if (innerSuite.removePhase(phaseClass)) { + if (innerSuite.phases.isEmpty()) { + it.remove(); + } + return true; + } + } + } + return false; + } + @Override protected void run(StructuredGraph graph, C context) { for (BasePhase phase : phases) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,7 @@ import com.oracle.graal.graph.Node; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu May 28 17:44:05 2015 +0200 @@ -33,7 +33,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.phases.*; import edu.umd.cs.findbugs.annotations.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Thu May 28 17:44:05 2015 +0200 @@ -362,6 +362,9 @@ } else if (obj instanceof Graph) { writeByte(PROPERTY_SUBGRAPH); writeGraph((Graph) obj); + } else if (obj instanceof CachedGraph) { + writeByte(PROPERTY_SUBGRAPH); + writeGraph(((CachedGraph) obj).getReadonlyCopy()); } else if (obj != null && obj.getClass().isArray()) { Class componentType = obj.getClass().getComponentType(); if (componentType.isPrimitive()) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DynamicNewArrayTest.java Thu May 28 17:44:05 2015 +0200 @@ -55,6 +55,7 @@ @Test public void test4() { test("dynamic", Boolean.class, -7); + test("dynamicSynchronized", Boolean.class, -7); } @Test @@ -95,4 +96,8 @@ public static Object dynamic(Class elementType, int length) { return Array.newInstance(elementType, length); } + + public static synchronized Object dynamicSynchronized(Class elementType, int length) { + return Array.newInstance(elementType, length); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Thu May 28 17:44:05 2015 +0200 @@ -412,4 +412,23 @@ test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"}); test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"}); } + + public int conditionalInstantiation(Object o) { + int total = 0; + if (o instanceof CharSequence) { + if (o instanceof StringBuilder || o instanceof String) { + total = 9; + } + total += (o instanceof String ? 2 : 1); + } + + return total; + } + + @Test + public void testInstantiation() { + test("conditionalInstantiation", "foo"); + test("conditionalInstantiation", new StringBuilder()); + test("conditionalInstantiation", 1); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Thu May 28 17:44:05 2015 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -50,7 +49,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015, 2015, 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.replacements.test; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.replacements.*; + +public class PEGraphDecoderTest extends GraalCompilerTest { + + /** + * This method is intrinsified to a node with a guard dependency on the block it is in. The + * various tests ensure that this guard is correctly updated when blocks are merged during + * inlining. + */ + private static native int readInt(Object obj, long offset); + + private static boolean flag; + private static int value; + + private static void invokeSimple() { + value = 111; + } + + private static void invokeComplicated() { + if (flag) { + value = 0; + } else { + value = 42; + } + } + + private static int readInt1(Object obj) { + return readInt(obj, 16); + } + + private static int readInt2(Object obj) { + invokeSimple(); + return readInt(obj, 16); + } + + private static int readInt3(Object obj) { + invokeComplicated(); + return readInt(obj, 16); + } + + private static int readInt4(Object obj, int n) { + if (n > 0) { + invokeComplicated(); + } + return readInt(obj, 16); + } + + public static int doTest(Object obj) { + int result = 0; + result += readInt1(obj); + result += readInt2(obj); + result += readInt3(obj); + result += readInt4(obj, 2); + return result; + } + + private static void registerPlugins(InvocationPlugins plugins) { + Registration r = new Registration(plugins, PEGraphDecoderTest.class); + r.register2("readInt", Object.class, long.class, new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, MethodIdMap.Receiver unused, ValueNode obj, ValueNode offset) { + LocationNode location = b.add(new ConstantLocationNode(LocationIdentity.any(), offset.asJavaConstant().asLong())); + ReadNode read = b.addPush(Kind.Int, new ReadNode(obj, location, StampFactory.forKind(Kind.Int), BarrierType.NONE)); + read.setGuard(AbstractBeginNode.prevBegin(read)); + return true; + } + }); + } + + class InlineAll implements InlineInvokePlugin { + @Override + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { + return new InlineInfo(method, false); + } + } + + @Test + public void test() { + ResolvedJavaMethod testMethod = getResolvedJavaMethod(PEGraphDecoderTest.class, "doTest", Object.class); + StructuredGraph targetGraph = null; + try (Debug.Scope scope = Debug.scope("GraphPETest", testMethod)) { + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault(getDefaultGraphBuilderPlugins()); + registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins()); + CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, getTarget().arch); + + targetGraph = new StructuredGraph(testMethod, AllowAssumptions.YES); + decoder.decode(targetGraph, testMethod, null, null, new InlineAll(), null); + Debug.dump(targetGraph, "Target Graph"); + targetGraph.verify(); + + PhaseContext context = new PhaseContext(getProviders()); + new CanonicalizerPhase().apply(targetGraph, context); + targetGraph.verify(); + + } catch (Throwable ex) { + if (targetGraph != null) { + Debug.dump(targetGraph, ex.toString()); + } + Debug.handle(ex); + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Thu May 28 17:44:05 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; import com.oracle.graal.word.nodes.*; @@ -56,7 +55,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/SubstitutionsTest.java Thu May 28 17:44:05 2015 +0200 @@ -39,6 +39,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; public class SubstitutionsTest extends GraalCompilerTest { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -45,7 +44,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null); } @Test diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.replacements; - -import static com.oracle.graal.api.code.BytecodeFrame.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; - -/** - * This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame - * state} per path. - * - * Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes - * in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid - * frame states}. - * - * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. - */ -public class CollapseFrameForSingleSideEffectPhase extends Phase { - - private static class IterationState { - public final IterationState previous; - public final Node node; - public final Collection merge; - public final boolean invalid; - - private IterationState(IterationState previous, Node node, Collection merge, boolean invalid) { - this.previous = previous; - this.node = node; - this.merge = merge; - this.invalid = invalid; - } - - public IterationState() { - this(null, null, null, false); - } - - public IterationState addSideEffect(StateSplit sideEffect) { - return new IterationState(this, sideEffect.asNode(), null, true); - } - - public IterationState addBranch(AbstractBeginNode begin) { - return new IterationState(this, begin, null, this.invalid); - } - - public static IterationState merge(AbstractMergeNode merge, Collection before, boolean invalid) { - return new IterationState(null, merge, before, invalid); - } - - public void markAll(NodeBitMap set) { - IterationState state = this; - while (state != null && state.node != null && !set.contains(state.node)) { - set.mark(state.node); - if (state.merge != null) { - for (IterationState branch : state.merge) { - branch.markAll(set); - } - } - state = state.previous; - } - } - - public void markMasked(NodeBitMap unmasked, NodeBitMap masked) { - IterationState state = this; - while (state != null && state.node != null && !masked.contains(state.node)) { - if (state.node instanceof StateSplit) { - unmasked.mark(state.node); - StateSplit split = (StateSplit) state.node; - if (split.hasSideEffect() && state.previous != null) { - state.previous.markAll(masked); - return; - } - } - - if (state.merge != null) { - for (IterationState branch : state.merge) { - branch.markMasked(unmasked, masked); - } - } - state = state.previous; - } - } - } - - @Override - protected void run(StructuredGraph graph) { - CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure(); - ReentrantNodeIterator.apply(closure, graph.start(), new IterationState()); - closure.finishProcessing(graph); - } - - private static class CollapseFrameForSingleSideEffectClosure extends NodeIteratorClosure { - - private List returnStates = new ArrayList<>(); - private List unwindStates = new ArrayList<>(); - - @Override - protected IterationState processNode(FixedNode node, IterationState currentState) { - IterationState state = currentState; - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (frameState != null) { - if (stateSplit.hasSideEffect()) { - setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false); - state = state.addSideEffect(stateSplit); - } else if (currentState.invalid) { - setStateAfter(node.graph(), stateSplit, INVALID_FRAMESTATE_BCI, false); - } else if (stateSplit instanceof StartNode) { - setStateAfter(node.graph(), stateSplit, BEFORE_BCI, false); - } else { - stateSplit.setStateAfter(null); - if (frameState.hasNoUsages()) { - GraphUtil.killWithUnusedFloatingInputs(frameState); - } - } - } - } - if (node instanceof ReturnNode) { - returnStates.add(currentState); - } else if (node instanceof UnwindNode) { - unwindStates.add(currentState); - } - return state; - } - - @Override - protected IterationState merge(AbstractMergeNode merge, List states) { - boolean invalid = false; - for (IterationState state : states) { - if (state.invalid) { - invalid = true; - break; - } - } - return IterationState.merge(merge, states, invalid); - } - - public void finishProcessing(StructuredGraph graph) { - NodeBitMap maskedSideEffects = new NodeBitMap(graph); - NodeBitMap returnSideEffects = new NodeBitMap(graph); - NodeBitMap unwindSideEffects = new NodeBitMap(graph); - - for (IterationState returnState : returnStates) { - returnState.markMasked(returnSideEffects, maskedSideEffects); - } - for (IterationState unwindState : unwindStates) { - unwindState.markMasked(unwindSideEffects, maskedSideEffects); - } - - for (Node returnSideEffect : returnSideEffects) { - if (!unwindSideEffects.contains(returnSideEffect) && !maskedSideEffects.contains(returnSideEffect)) { - StateSplit split = (StateSplit) returnSideEffect; - setStateAfter(graph, split, AFTER_BCI, true); - } - } - - for (Node unwindSideEffect : unwindSideEffects) { - if (!returnSideEffects.contains(unwindSideEffect) && !maskedSideEffects.contains(unwindSideEffect)) { - StateSplit split = (StateSplit) unwindSideEffect; - setStateAfter(graph, split, AFTER_EXCEPTION_BCI, true); - } - } - } - - @Override - protected IterationState afterSplit(AbstractBeginNode node, IterationState oldState) { - return oldState.addBranch(node); - } - - @Override - protected Map processLoop(LoopBeginNode loop, IterationState initialState) { - LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, initialState); - - boolean isNowInvalid = initialState.invalid; - for (IterationState endState : info.endStates.values()) { - isNowInvalid |= endState.invalid; - } - - if (isNowInvalid) { - setStateAfter(loop.graph(), loop, INVALID_FRAMESTATE_BCI, false); - } - - IterationState endState = IterationState.merge(loop, info.endStates.values(), isNowInvalid); - return ReentrantNodeIterator.processLoop(this, loop, endState).exitStates; - } - - /** - * Creates and sets a special frame state for a node. If the existing frame state is - * non-null and has no other usages, it is deleted via - * {@link GraphUtil#killWithUnusedFloatingInputs(Node)}. - * - * @param graph the graph context - * @param node the node whose frame state is updated - * @param bci {@link BytecodeFrame#BEFORE_BCI}, {@link BytecodeFrame#AFTER_EXCEPTION_BCI} or - * {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} - * @param replaceOnly only perform the update if the node currently has a non-null frame - * state - */ - private static void setStateAfter(StructuredGraph graph, StateSplit node, int bci, boolean replaceOnly) { - assert (bci == BEFORE_BCI && node instanceof StartNode) || bci == AFTER_BCI || bci == AFTER_EXCEPTION_BCI || bci == INVALID_FRAMESTATE_BCI; - FrameState currentStateAfter = node.stateAfter(); - if (currentStateAfter != null || !replaceOnly) { - node.setStateAfter(graph.add(new FrameState(bci))); - if (currentStateAfter != null && currentStateAfter.hasNoUsages()) { - GraphUtil.killWithUnusedFloatingInputs(currentStateAfter); - } - } - } - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -73,9 +73,9 @@ } public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if (b.parsingReplacement() && wordOperationPlugin.apply(b, method, args)) { + if (b.parsingIntrinsic() && wordOperationPlugin.apply(b, method, args)) { return true; - } else if (b.parsingReplacement()) { + } else if (b.parsingIntrinsic()) { NodeIntrinsic intrinsic = nodeIntrinsification.getIntrinsic(method); if (intrinsic != null) { Signature sig = method.getSignature(); @@ -145,12 +145,18 @@ b.add(new UnsafeStoreNode(copy.destinationObject(), copy.destinationOffset(), value, copy.accessKind(), copy.getLocationIdentity())); return true; } else if (res instanceof ForeignCallNode) { - ForeignCallNode foreign = (ForeignCallNode) res; - foreign.setBci(b.bci()); + /* + * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the + * case that the foreign call can deoptimize. As with all deoptimization, we need a + * state in a non-intrinsic method. + */ + GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor(); + if (nonIntrinsicAncestor != null) { + ForeignCallNode foreign = (ForeignCallNode) res; + foreign.setBci(nonIntrinsicAncestor.bci()); + } } - res = b.add(res); - boolean nonValueType = false; if (returnKind == Kind.Object && stamp instanceof ObjectStamp) { ResolvedJavaType type = ((ObjectStamp) stamp).type(); @@ -162,16 +168,10 @@ if (returnKind != Kind.Void) { assert nonValueType || res.getKind().getStackKind() != Kind.Void; - b.push(returnKind.getStackKind(), res); + res = b.addPush(returnKind.getStackKind(), res); } else { assert res.getKind().getStackKind() == Kind.Void; - } - - if (res instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) res; - if (stateSplit.stateAfter() == null) { - stateSplit.setStateAfter(b.createStateAfter()); - } + res = b.add(res); } return true; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Thu May 28 17:44:05 2015 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.replacements; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graphbuilderconf.*; @@ -39,8 +39,9 @@ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType); if (inlineInfo == null) { - if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { - return new InlineInfo(method, false, false); + if (InlineDuringParsing.getValue() && method.hasBytecodes() && !method.isSynchronized() && method.getCode().length <= TrivialInliningSize.getValue() && + b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { + return new InlineInfo(method, false); } } return inlineInfo; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -38,11 +38,12 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -143,13 +144,8 @@ ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object(); ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value()); ConstantLocationNode location = createFieldLocation(graph, field, false); + assert location != null; - if (location == null) { - /* Field has been eliminated, so no write necessary. */ - assert !storeField.isVolatile() : "missing memory barriers"; - graph.removeFixed(storeField); - return; - } WriteNode memoryWrite = graph.add(new WriteNode(object, value, location, fieldStoreBarrierType(storeField.field()))); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Thu May 28 17:44:05 2015 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.replacements; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; + import java.lang.reflect.*; import java.util.*; @@ -89,7 +91,7 @@ } public T changeToWord(T node) { - if (wordTypes.isWord(node)) { + if (wordTypes != null && wordTypes.isWord(node)) { node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node))); } return node; @@ -123,8 +125,13 @@ * @param name the name of the invoked method * @param args the arguments to the invocation */ - public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { boolean isStatic = invokeKind == InvokeKind.Static; + ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic); + return createInvoke(method, invokeKind, frameStateBuilder, bci, args); + } + + public ResolvedJavaMethod findMethod(Class declaringClass, String name, boolean isStatic) { ResolvedJavaMethod method = null; for (Method m : declaringClass.getDeclaredMethods()) { if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) { @@ -133,14 +140,14 @@ } } assert method != null : "did not find method in " + declaringClass + " named " + name; - return createInvoke(method, invokeKind, frameStateBuilder, bci, args); + return method; } /** * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of * arguments. */ - public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { assert method.isStatic() == (invokeKind == InvokeKind.Static); Signature signature = method.getSignature(); JavaType returnType = signature.getReturnType(null); @@ -152,7 +159,7 @@ if (invoke.getKind() != Kind.Void) { frameStateBuilder.push(returnType.getKind(), invoke); } - invoke.setStateAfter(frameStateBuilder.create(bci)); + invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); if (invoke.getKind() != Kind.Void) { frameStateBuilder.pop(returnType.getKind()); } @@ -179,12 +186,14 @@ } int argIndex = 0; if (!isStatic) { - Kind expected = wordTypes.asKind(method.getDeclaringClass()); + ResolvedJavaType expectedType = method.getDeclaringClass(); + Kind expected = wordTypes == null ? expectedType.getKind() : wordTypes.asKind(expectedType); Kind actual = args[argIndex++].stamp().getStackKind(); assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]"; } for (int i = 0; i != signature.getParameterCount(false); i++) { - Kind expected = wordTypes.asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind(); + JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass()); + Kind expected = wordTypes == null ? expectedType.getKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind(); Kind actual = args[argIndex++].stamp().getStackKind(); if (expected != actual) { throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]"); @@ -219,7 +228,7 @@ GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO); - IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, INLINE_AFTER_PARSING); new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph); // Remove all frame states from inlinee diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Thu May 28 17:44:05 2015 +0200 @@ -96,7 +96,17 @@ protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) { InstanceOfUsageReplacer replacer; if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode || usage instanceof ConditionAnchorNode) { - replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage); + ValueNode trueValue = ConstantNode.forInt(1, graph); + ValueNode falseValue = ConstantNode.forInt(0, graph); + if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) { + /* + * This code doesn't really care what values are used so adopt the values from the + * previous instantiation. + */ + trueValue = instantiation.trueValue; + falseValue = instantiation.falseValue; + } + replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage); } else { assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; ConditionalNode c = (ConditionalNode) usage; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java Thu May 28 17:44:05 2015 +0200 @@ -152,8 +152,10 @@ return graph; } - public FrameState createStateAfter() { - return getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI)); + public void setStateAfter(StateSplit sideEffect) { + assert sideEffect.hasSideEffect(); + FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI)); + sideEffect.setStateAfter(stateAfter); } public GraphBuilderContext getParent() { @@ -180,11 +182,11 @@ return 0; } - public boolean parsingReplacement() { + public boolean parsingIntrinsic() { return true; } - public Replacement getReplacement() { + public IntrinsicContext getIntrinsic() { throw GraalInternalError.shouldNotReachHere(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 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.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; +import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.replacements.nodes.*; + +public class MethodHandleInvocationPlugin implements GenericInvocationPlugin { + private final MethodHandleAccessProvider methodHandleAccess; + private final GenericInvocationPlugin delegate; + + public MethodHandleInvocationPlugin(MethodHandleAccessProvider methodHandleAccess, GenericInvocationPlugin delegate) { + this.methodHandleAccess = methodHandleAccess; + this.delegate = delegate; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + InvokeKind invokeKind = b.getInvokeKind(); + if (invokeKind != InvokeKind.Static) { + args[0] = b.nullCheckedValue(args[0]); + } + JavaType invokeReturnType = b.getInvokeReturnType(); + InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args); + if (invoke == null) { + MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args); + if (invokeReturnType.getKind() == Kind.Void) { + b.add(methodHandleNode); + } else { + b.addPush(methodHandleNode); + } + } else { + CallTargetNode callTarget = invoke.callTarget(); + NodeInputList argumentsList = callTarget.arguments(); + ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]); + for (ValueNode arg : newArgs) { + b.recursiveAppend(arg); + } + b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs); + } + return true; + } + return delegate.apply(b, method, args); + } +} diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Thu May 28 17:44:05 2015 +0200 @@ -120,7 +120,7 @@ return true; } - @SuppressWarnings("serial") public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) { + public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) { @Override public boolean equals(Object o) { return this == o; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Thu May 28 17:44:05 2015 +0200 @@ -23,13 +23,14 @@ package com.oracle.graal.replacements; import static com.oracle.graal.compiler.common.GraalInternalError.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.graphbuilderconf.*; @@ -97,6 +98,15 @@ public boolean isInlinedMethod() { return caller != null; } + + public BytecodePosition getBytecodePosition() { + if (bytecodePosition == null) { + ensureOuterStateDecoded(this); + ensureExceptionStateDecoded(this); + bytecodePosition = InliningUtil.processBytecodePosition(invokeData.invoke, null); + } + return bytecodePosition; + } } protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { @@ -139,7 +149,7 @@ } @Override - public Replacement getReplacement() { + public IntrinsicContext getIntrinsic() { return null; } @@ -169,7 +179,7 @@ } @Override - public FrameState createStateAfter() { + public void setStateAfter(StateSplit stateSplit) { throw unimplemented(); } @@ -217,10 +227,11 @@ } @Override - public FrameState createStateAfter() { + public void setStateAfter(StateSplit stateSplit) { Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); getGraph().add(stateAfter); - return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); + stateSplit.setStateAfter(fs); } @Override @@ -379,7 +390,7 @@ if (graphBuilderContext.lastInstr != null) { registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); - graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData)); + graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr))); } else { assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; invoke.asNode().replaceAtUsages(null); @@ -411,7 +422,7 @@ if (inlineInfo == null) { return false; } - assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported"; + assert !inlineInfo.isIntrinsic : "not supported"; ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline; EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod); @@ -458,16 +469,16 @@ ValueNode returnValue; List returnNodes = inlineScope.returnNodes; if (!returnNodes.isEmpty()) { - FixedNode n; - n = nodeAfterInvoke(methodScope, loopScope, invokeData); if (returnNodes.size() == 1) { ReturnNode returnNode = returnNodes.get(0); returnValue = returnNode.result(); + FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode)); returnNode.replaceAndDelete(n); } else { AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); returnValue = InliningUtil.mergeReturns(merge, returnNodes, null); + FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge); merge.setNext(n); } } else { @@ -484,17 +495,24 @@ registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); } if (inlineScope.exceptionPlaceholderNode != null) { - inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue); + inlineScope.exceptionPlaceholderNode.replaceAtUsages(exceptionValue); + inlineScope.exceptionPlaceholderNode.safeDelete(); } deleteInvoke(invoke); methodScope.inlineInvokePlugin.postInline(inlineMethod); + + if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) { + Debug.dump(methodScope.graph, "Inline finished: " + inlineMethod.getDeclaringClass().getUnqualifiedName() + "." + inlineMethod.getName()); + } return true; } - public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) { + assert lastBlock.isAlive(); FixedNode n; if (invokeData.invoke instanceof InvokeWithExceptionNode) { + registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false); n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); } else { n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); @@ -518,6 +536,15 @@ protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method); @Override + protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { + PEMethodScope methodScope = (PEMethodScope) s; + if (node instanceof SimpleInfopointNode && methodScope.isInlinedMethod()) { + InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.getBytecodePosition()); + } + super.handleFixedNode(s, loopScope, nodeOrderId, node); + } + + @Override protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { PEMethodScope methodScope = (PEMethodScope) s; @@ -590,11 +617,7 @@ PEMethodScope methodScope = (PEMethodScope) s; if (methodScope.isInlinedMethod()) { - if (node instanceof SimpleInfopointNode) { - methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition); - return node; - - } else if (node instanceof FrameState) { + if (node instanceof FrameState) { FrameState frameState = (FrameState) node; ensureOuterStateDecoded(methodScope); diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Thu May 28 17:44:05 2015 +0200 @@ -24,7 +24,8 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import static java.lang.String.*; @@ -45,7 +46,6 @@ import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPhase.Instance; import com.oracle.graal.nodes.*; @@ -77,6 +77,10 @@ this.graphBuilderPlugins = plugins; } + public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() { + return graphBuilderPlugins; + } + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null; } @@ -93,13 +97,13 @@ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { ResolvedJavaMethod subst = getSubstitutionMethod(method); if (subst != null) { - if (b.parsingReplacement() || InlineDuringParsing.getValue() || InlineIntrinsicsDuringParsing.getValue()) { + if (b.parsingIntrinsic() || InlineDuringParsing.getValue() || InlineIntrinsicsDuringParsing.getValue()) { // Forced inlining of intrinsics - return new InlineInfo(subst, true, true); + return new InlineInfo(subst, true); } return null; } - if (b.parsingReplacement()) { + if (b.parsingIntrinsic()) { assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; @@ -110,7 +114,7 @@ } // Force inlining when parsing replacements - return new InlineInfo(method, true, true); + return new InlineInfo(method, true); } else { assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), method.format("%h.%n"), b); @@ -119,10 +123,10 @@ } public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { - if (b.parsingReplacement()) { - Replacement replacement = b.getReplacement(); - assert replacement.isCallToOriginal(method) : format("All non-recursive calls in the replacement %s must be inlined or intrinsified: found call to %s", - replacement.getReplacementMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)")); + if (b.parsingIntrinsic()) { + IntrinsicContext intrinsic = b.getIntrinsic(); + assert intrinsic.isCallToOriginal(method) : format("All non-recursive calls in the intrinsic %s must be inlined or intrinsified: found call to %s", + intrinsic.getIntrinsicMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)")); } } @@ -131,7 +135,6 @@ */ protected class ClassReplacements { public final Map methodSubstitutions = CollectionsFactory.newMap(); - public final Set forcedSubstitutions = new HashSet<>(); public ClassReplacements(Class[] substitutionClasses, AtomicReference ref) { for (Class substitutionClass : substitutionClasses) { @@ -168,10 +171,7 @@ if (originalMethods != null) { for (Executable originalMethod : originalMethods) { if (originalMethod != null && (guard == null || guard.execute())) { - ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod); - if (original != null && methodSubstitution.forced()) { - forcedSubstitutions.add(original); - } + registerMethodSubstitution(this, originalMethod, substituteMethod); } } } @@ -299,9 +299,7 @@ StructuredGraph graph = UseSnippetGraphCache ? graphs.get(method) : null; if (graph == null) { try (DebugCloseable a = SnippetPreparationTime.start()) { - FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal - : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, args, recursiveEntry); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache || args != null) { return newGraph; @@ -346,7 +344,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, null, original, FrameStateProcessing.None); + graph = makeGraph(substitute, null, original); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -445,36 +443,18 @@ * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null - * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) { try (OverrideScope s = OptionValue.override(DeoptALot, false)) { - return createGraphMaker(method, original, frameStateProcessing).makeGraph(args); + return createGraphMaker(method, original).makeGraph(args); } } /** * Can be overridden to return an object that specializes various parts of graph preprocessing. */ - protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { - return new GraphMaker(this, substitute, original, frameStateProcessing); - } - - /** - * Cache to speed up preprocessing of replacement graphs. - */ - final ConcurrentMap graphCache = new ConcurrentHashMap<>(); - - public enum FrameStateProcessing { - None, - /** - * @see CollapseFrameForSingleSideEffectPhase - */ - CollapseFrameForSingleSideEffect, - /** - * Removes frame states from all nodes in the graph. - */ - Removal + protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) { + return new GraphMaker(this, substitute, original); } /** @@ -496,26 +476,16 @@ */ protected final ResolvedJavaMethod substitutedMethod; - /** - * Controls how FrameStates are processed. - */ - private FrameStateProcessing frameStateProcessing; - - protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, FrameStateProcessing frameStateProcessing) { + protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) { this.replacements = replacements; this.method = substitute; this.substitutedMethod = substitutedMethod; - this.frameStateProcessing = frameStateProcessing; } public StructuredGraph makeGraph(Object[] args) { try (Scope s = Debug.scope("BuildSnippetGraph", method)) { - StructuredGraph graph = parseGraph(method, args); - - if (args == null) { - // Cannot have a finalized version of a graph in the cache - graph = graph.copy(); - } + assert method.hasBytecodes() : method; + StructuredGraph graph = buildInitialGraph(method, args); finalizeGraph(graph); @@ -536,18 +506,6 @@ new ConvertDeoptimizeToGuardPhase().apply(graph, null); assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node"; - switch (frameStateProcessing) { - case Removal: - for (Node node : graph.getNodes()) { - if (node instanceof StateSplit) { - ((StateSplit) node).setStateAfter(null); - } - } - break; - case CollapseFrameForSingleSideEffect: - new CollapseFrameForSingleSideEffectPhase().apply(graph); - break; - } new DeadCodeEliminationPhase(Required).apply(graph); } @@ -580,21 +538,6 @@ return false; } - private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) { - assert methodToParse.hasBytecodes() : methodToParse; - if (args != null) { - return buildInitialGraph(methodToParse, args); - } - StructuredGraph graph = replacements.graphCache.get(methodToParse); - if (graph == null) { - StructuredGraph newGraph = buildInitialGraph(methodToParse, args); - replacements.graphCache.putIfAbsent(methodToParse, newGraph); - graph = replacements.graphCache.get(methodToParse); - assert graph != null; - } - return graph; - } - /** * Builds the initial graph for a snippet. */ @@ -614,7 +557,19 @@ if (args != null) { plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection)); } - createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE).apply(graph); + + IntrinsicContext initialIntrinsicContext = null; + if (method.getAnnotation(Snippet.class) == null) { + // Post-parse inlined intrinsic + initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING); + } else { + // Snippet + ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; + initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING); + } + + createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply( + graph); if (OptCanonicalizer.getValue()) { new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers)); @@ -626,17 +581,8 @@ } protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts) { - ReplacementContext initialReplacementContext = null; - if (method.getAnnotation(Snippet.class) == null) { - // Late inlined intrinsic - initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1); - } else { - // Snippet - ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; - initialReplacementContext = new ReplacementContext(original, method); - } - return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); + OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } } @@ -713,12 +659,6 @@ return result; } - @Override - public boolean isForcedSubstitution(ResolvedJavaMethod method) { - ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName()); - return cr != null && cr.forcedSubstitutions.contains(method); - } - public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int callerBci) { if (!fromBytecodeOnly) { InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounterNode.java Thu May 28 17:44:05 2015 +0200 @@ -22,9 +22,12 @@ */ package com.oracle.graal.replacements; +import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.common.UnsafeAccess.*; import static com.oracle.graal.replacements.SnippetTemplate.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; @@ -35,6 +38,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.util.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; @@ -85,6 +89,34 @@ } } + /** + * When {@link #SnippetCounters} are enabled make sure {@link #SNIPPET_COUNTER_LOCATION} is part + * of the private locations. + * + * @param privateLocations + * @return a copy of privateLocations with any needed locations added + */ + public static LocationIdentity[] addSnippetCounters(LocationIdentity[] privateLocations) { + if (SnippetCounters.getValue()) { + for (LocationIdentity location : privateLocations) { + if (location.equals(SNIPPET_COUNTER_LOCATION)) { + return privateLocations; + } + } + LocationIdentity[] result = Arrays.copyOf(privateLocations, privateLocations.length + 1); + result[result.length - 1] = SnippetCounterNode.SNIPPET_COUNTER_LOCATION; + return result; + } + return privateLocations; + } + + /** + * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value} field, + * so that the usage in snippets is always possible. If a method accesses the counter via the + * field and the snippet, the result might not be correct though. + */ + public static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter"); + static class SnippetCounterSnippets implements Snippets { @Fold @@ -96,15 +128,8 @@ } } - /** - * We do not want to use the {@link LocationIdentity} of the {@link SnippetCounter#value} - * field, so that the usage in snippets is always possible. If a method accesses the counter - * via the field and the snippet, the result might not be correct though. - */ - protected static final LocationIdentity SNIPPET_COUNTER_LOCATION = NamedLocationIdentity.mutable("SnippetCounter"); - @Snippet - public static void add(SnippetCounter counter, int increment) { + public static void add(@ConstantParameter SnippetCounter counter, int increment) { long loadedValue = ObjectAccess.readLong(counter, countOffset(), SNIPPET_COUNTER_LOCATION); ObjectAccess.writeLong(counter, countOffset(), loadedValue + increment, SNIPPET_COUNTER_LOCATION); } diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Thu May 28 17:44:05 2015 +0200 @@ -52,8 +52,8 @@ import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.StructuredGraph.GuardsStage; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.common.*; @@ -87,6 +87,7 @@ public abstract static class SnippetInfo { protected final ResolvedJavaMethod method; + protected ResolvedJavaMethod original; protected final LocationIdentity[] privateLocations; /** @@ -150,7 +151,7 @@ protected SnippetInfo(ResolvedJavaMethod method, LocationIdentity[] privateLocations) { this.method = method; - this.privateLocations = privateLocations; + this.privateLocations = SnippetCounterNode.addSnippetCounters(privateLocations); instantiationCounter = Debug.metric("SnippetInstantiationCount[%s]", method.getName()); instantiationTimer = Debug.timer("SnippetInstantiationTime[%s]", method.getName()); assert method.isStatic() : "snippet method must be static: " + method.format("%H.%n"); @@ -175,6 +176,10 @@ return lazy().constantParameters.length; } + public void setOriginalMethod(ResolvedJavaMethod original) { + this.original = original; + } + public boolean isConstantParameter(int paramIdx) { return lazy().constantParameters[paramIdx]; } @@ -190,6 +195,11 @@ } return null; } + + @Override + public String toString() { + return getClass().getSimpleName() + ":" + method.format("%h.%n"); + } } protected static class LazySnippetInfo extends SnippetInfo { @@ -263,6 +273,7 @@ } public Arguments addConst(String name, Object value) { + assert value != null; return addConst(name, value, null); } @@ -560,7 +571,7 @@ this.info = args.info; Object[] constantArgs = getConstantArgs(args); - StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, constantArgs); + StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs); instantiationTimer = Debug.timer("SnippetTemplateInstantiationTime[%#s]", args); instantiationCounter = Debug.metric("SnippetTemplateInstantiationCount[%#s]", args); @@ -781,6 +792,8 @@ for (int i = 0; i < args.info.getParameterCount(); i++) { if (!args.info.isConstantParameter(i)) { constantArgs[i] = null; + } else { + assert constantArgs[i] != null : "Can't pass raw null through as argument"; } } return constantArgs; @@ -1098,11 +1111,12 @@ // rewire outgoing memory edges replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates)); - ReturnNode ret = (ReturnNode) duplicates.get(returnNode); - MemoryMapNode memoryMap = ret.getMemoryMap(); - ret.setMemoryMap(null); - memoryMap.safeDelete(); - + if (returnNode != null) { + ReturnNode ret = (ReturnNode) duplicates.get(returnNode); + MemoryMapNode memoryMap = ret.getMemoryMap(); + ret.setMemoryMap(null); + memoryMap.safeDelete(); + } if (memoryAnchor != null) { // rewire incoming memory edges MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor); @@ -1298,7 +1312,7 @@ * Gets a copy of the specialized graph. */ public StructuredGraph copySpecializedGraph() { - return snippet.copy(); + return (StructuredGraph) snippet.copy(); } /** diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Thu May 28 17:44:05 2015 +0200 @@ -84,6 +84,7 @@ if (Options.UseBlackholeSubstitution.getValue()) { registerJMHBlackholePlugins(plugins); } + registerJFRThrowablePlugins(plugins); } private static final Field STRING_VALUE_FIELD; @@ -459,7 +460,7 @@ } public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { - if (b.parsingReplacement()) { + if (b.parsingIntrinsic()) { ResolvedJavaMethod rootMethod = b.getGraph().method(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { // Disable invocation plugins for boxing snippets so that the @@ -486,7 +487,7 @@ } public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - if (b.parsingReplacement()) { + if (b.parsingIntrinsic()) { ResolvedJavaMethod rootMethod = b.getGraph().method(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { // Disable invocation plugins for unboxing snippets so that the @@ -651,4 +652,18 @@ } } } + + private static void registerJFRThrowablePlugins(InvocationPlugins plugins) { + String name = "oracle.jrockit.jfr.jdkevents.ThrowableTracer"; + Class tracerClass = MethodSubstitutionPlugin.resolveClass(name, true); + if (tracerClass != null) { + Registration r = new Registration(plugins, tracerClass); + r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) { + b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), throwable, message)); + return true; + } + }); + } + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2015, 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 @@ -34,9 +34,9 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -28,7 +28,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -22,44 +22,109 @@ */ package com.oracle.graal.replacements.nodes; +import static com.oracle.graal.api.meta.LocationIdentity.*; + import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; @NodeInfo -public abstract class BasicArrayCopyNode extends MacroStateSplitNode implements Virtualizable { +public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring { public static final NodeClass TYPE = NodeClass.create(BasicArrayCopyNode.class); - public BasicArrayCopyNode(NodeClass c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { - super(c, invokeKind, targetMethod, bci, returnType, arguments); + @Input protected ValueNode src; + @Input protected ValueNode srcPos; + @Input protected ValueNode dest; + @Input protected ValueNode destPos; + @Input protected ValueNode length; + + @OptionalInput(InputType.State) FrameState stateDuring; + + @OptionalInput(InputType.Memory) protected MemoryNode lastLocationAccess; + + protected Kind elementKind; + + protected int bci; + + public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, int bci) { + super(type, StampFactory.forKind(Kind.Void)); + this.bci = bci; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.elementKind = elementKind != Kind.Illegal ? elementKind : null; } - protected ValueNode getSource() { - return arguments.get(0); + public BasicArrayCopyNode(NodeClass type, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) { + super(type, StampFactory.forKind(Kind.Void)); + this.bci = -6; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.elementKind = elementKind != Kind.Illegal ? elementKind : null; + } + + public ValueNode getSource() { + return src; } - protected ValueNode getSourcePosition() { - return arguments.get(1); + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + public ValueNode getLength() { + return length; + } + + public int getBci() { + return bci; } - protected ValueNode getDestination() { - return arguments.get(2); + public Kind getElementKind() { + return elementKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); } - protected ValueNode getDestinationPosition() { - return arguments.get(3); + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; } - protected ValueNode getLength() { - return arguments.get(4); + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); } private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { @@ -89,16 +154,37 @@ return true; } + /* + * Returns true if this copy doesn't require store checks. Trivially true for primitive arrays. + */ + public boolean isExact() { + ResolvedJavaType srcType = StampTool.typeOrNull(getSource().stamp()); + ResolvedJavaType destType = StampTool.typeOrNull(getDestination().stamp()); + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return false; + } + if (srcType.getComponentType().getKind().isPrimitive() || getSource() == getDestination()) { + return true; + } + + if (StampTool.isExactType(getDestination().stamp())) { + if (destType != null && destType.isAssignableFrom(srcType)) { + return true; + } + } + return false; + } + @Override public void virtualize(VirtualizerTool tool) { ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition()); ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition()); - ValueNode length = tool.getReplacedValue(getLength()); + ValueNode replacedLength = tool.getReplacedValue(getLength()); - if (sourcePosition.isConstant() && destinationPosition.isConstant() && length.isConstant()) { - int srcPos = sourcePosition.asJavaConstant().asInt(); - int destPos = destinationPosition.asJavaConstant().asInt(); - int len = length.asJavaConstant().asInt(); + if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { + int srcPosInt = sourcePosition.asJavaConstant().asInt(); + int destPosInt = destinationPosition.asJavaConstant().asInt(); + int len = replacedLength.asJavaConstant().asInt(); State destState = tool.getObjectState(getDestination()); if (destState != null && destState.getState() == EscapeState.Virtual) { @@ -106,7 +192,7 @@ if (!(destVirtual instanceof VirtualArrayNode)) { return; } - if (len < 0 || !checkBounds(destPos, len, destVirtual)) { + if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { return; } State srcState = tool.getObjectState(getSource()); @@ -121,18 +207,18 @@ if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) { return; } - if (!checkBounds(srcPos, len, srcVirtual)) { + if (!checkBounds(srcPosInt, len, srcVirtual)) { return; } - if (!checkEntryTypes(srcPos, len, srcState, destVirtual.type().getComponentType(), tool)) { + if (!checkEntryTypes(srcPosInt, len, srcState, destVirtual.type().getComponentType(), tool)) { return; } for (int i = 0; i < len; i++) { - tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i), false); + tool.setVirtualEntry(destState, destPosInt + i, srcState.getEntry(srcPosInt + i), false); } tool.delete(); if (Debug.isLogEnabled()) { - Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, len); + Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); } } else { ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue(); @@ -146,13 +232,31 @@ return; } for (int i = 0; i < len; i++) { - LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPos, graph()), destComponentType.getKind()); + LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); tool.addNode(load); - tool.setVirtualEntry(destState, destPos + i, load, false); + tool.setVirtualEntry(destState, destPosInt + i, load, false); } tool.delete(); } } } } + + public boolean canDeoptimize() { + return true; + } + + public FrameState stateDuring() { + return stateDuring; + } + + public void setStateDuring(FrameState stateDuring) { + updateUsages(this.stateDuring, stateDuring); + this.stateDuring = stateDuring; + } + + public void computeStateDuring(FrameState currentStateAfter) { + FrameState newStateDuring = currentStateAfter.duplicateModifiedDuringCall(getBci(), asNode().getKind()); + setStateDuring(newStateDuring); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -27,8 +27,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; import com.oracle.graal.nodes.spi.*; /** diff -r 107300758a4e -r 28cbfacd0518 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 Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu May 28 17:44:05 2015 +0200 @@ -24,7 +24,6 @@ import static com.oracle.graal.api.code.BytecodeFrame.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; @@ -113,14 +112,7 @@ protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) { StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci); if (methodSubstitution != null) { - methodSubstitution = methodSubstitution.copy(); - if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) { - /* - * handles the case of a MacroNode inside a snippet used for another MacroNode - * lowering - */ - new CollapseFrameForSingleSideEffectPhase().apply(methodSubstitution); - } + methodSubstitution = (StructuredGraph) methodSubstitution.copy(); return lowerReplacement(methodSubstitution, tool); } return null; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java Thu May 28 17:44:05 2015 +0200 @@ -29,8 +29,8 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; /** * This is an extension of {@link MacroNode} that is a {@link StateSplit} and a diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements.nodes; + +import java.lang.invoke.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.Assumptions.AssumptionResult; +import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * Node for invocation methods defined on the class {@link MethodHandle}. + */ +@NodeInfo +public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable { + public static final NodeClass TYPE = NodeClass.create(MethodHandleNode.class); + + protected final IntrinsicMethod intrinsicMethod; + + public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { + super(TYPE, invokeKind, targetMethod, bci, returnType, arguments); + this.intrinsicMethod = intrinsicMethod; + } + + /** + * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an + * invocation on another method with possibly transformed arguments. + * + * @param assumptions object for recording any speculations made during the transformation + * @param methodHandleAccess objects for accessing the implementation internals of a + * {@link MethodHandle} + * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed + * @param bci the BCI of the original {@link MethodHandle} call + * @param returnType return type of the original {@link MethodHandle} call + * @param arguments arguments to the original {@link MethodHandle} call + * @return a more direct invocation derived from the {@link MethodHandle} call or null + */ + public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode... arguments) { + switch (intrinsicMethod) { + case INVOKE_BASIC: + return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); + case LINK_TO_STATIC: + case LINK_TO_SPECIAL: + case LINK_TO_VIRTUAL: + case LINK_TO_INTERFACE: + return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public void simplify(SimplifierTool tool) { + MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess(); + ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]); + InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray); + if (invoke != null) { + assert invoke.graph() == null; + invoke = graph().addOrUniqueWithInputs(invoke); + invoke.setStateAfter(stateAfter()); + FixedNode currentNext = next(); + replaceAtUsages(invoke); + GraphUtil.removeFixedWithUnusedInputs(this); + graph().addBeforeFixed(currentNext, invoke); + } + } + + /** + * Get the receiver of a MethodHandle.invokeBasic call. + * + * @return the receiver argument node + */ + private static ValueNode getReceiver(ValueNode[] arguments) { + return arguments[0]; + } + + /** + * Get the MemberName argument of a MethodHandle.linkTo* call. + * + * @return the MemberName argument node (which is the last argument) + */ + private static ValueNode getMemberName(ValueNode[] arguments) { + return arguments[arguments.length - 1]; + } + + /** + * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC } + * method) to get the target {@link InvokeNode} if the method handle receiver is constant. + * + * @return invoke node for the {@link java.lang.invoke.MethodHandle} target + */ + private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode[] arguments) { + ValueNode methodHandleNode = getReceiver(arguments); + if (methodHandleNode.isConstant()) { + return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original); + } + return null; + } + + /** + * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC}, + * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and + * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if + * the member name argument is constant. + * + * @return invoke node for the member name target + */ + private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode[] arguments) { + ValueNode memberNameNode = getMemberName(arguments); + if (memberNameNode.isConstant()) { + return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original); + } + return null; + } + + /** + * Helper function to get the {@link InvokeNode} for the targetMethod of a + * java.lang.invoke.MemberName. + * + * @param target the target, already loaded from the member name node + * @return invoke node for the member name target + */ + private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target, + ResolvedJavaMethod original) { + if (target == null) { + return null; + } + + // In lambda forms we erase signature types to avoid resolving issues + // involving class loaders. When we optimize a method handle invoke + // to a direct call we must cast the receiver and arguments to its + // actual types. + Signature signature = target.getSignature(); + final boolean isStatic = target.isStatic(); + final int receiverSkip = isStatic ? 0 : 1; + + // Cast receiver to its type. + if (!isStatic) { + JavaType receiverType = target.getDeclaringClass(); + maybeCastArgument(arguments, 0, receiverType); + } + + // Cast reference arguments to its type. + for (int index = 0; index < signature.getParameterCount(false); index++) { + JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass()); + maybeCastArgument(arguments, receiverSkip + index, parameterType); + } + + if (target.canBeStaticallyBound()) { + return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments); + } + + // Try to get the most accurate receiver type + if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) { + ValueNode receiver = getReceiver(arguments); + ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp()); + if (receiverType != null) { + AssumptionResult concreteMethod = receiverType.findUniqueConcreteMethod(target); + if (concreteMethod != null) { + assumptions.record(concreteMethod); + return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); + } + } + } else { + AssumptionResult concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target); + if (concreteMethod != null) { + assumptions.record(concreteMethod); + return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); + } + } + + return null; + } + + /** + * Inserts a node to cast the argument at index to the given type if the given type is more + * concrete than the argument type. + * + * @param index of the argument to be cast + * @param type the type the argument should be cast to + */ + private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) { + if (type instanceof ResolvedJavaType) { + ResolvedJavaType targetType = (ResolvedJavaType) type; + if (!targetType.isPrimitive()) { + ValueNode argument = arguments[index]; + ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp()); + if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) { + PiNode piNode = new PiNode(argument, StampFactory.declared(targetType)); + arguments[index] = piNode; + } + } + } + } + + /** + * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed + * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}. + * + * @return invoke node for the member name target + */ + private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) { + InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special; + JavaType targetReturnType = target.getSignature().getReturnType(null); + + // MethodHandleLinkTo* nodes have a trailing MemberName argument which + // needs to be popped. + ValueNode[] targetArguments; + switch (intrinsicMethod) { + case INVOKE_BASIC: + targetArguments = arguments; + break; + case LINK_TO_STATIC: + case LINK_TO_SPECIAL: + case LINK_TO_VIRTUAL: + case LINK_TO_INTERFACE: + targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType); + + // The call target can have a different return type than the invoker, + // e.g. the target returns an Object but the invoker void. In this case + // we need to use the stamp of the invoker. Note: always using the + // invoker's stamp would be wrong because it's a less concrete type + // (usually java.lang.Object). + if (returnType.getKind() == Kind.Void) { + return new InvokeNode(callTarget, bci, StampFactory.forVoid()); + } else { + return new InvokeNode(callTarget, bci); + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements.nodes; + +import static sun.misc.Version.*; + +import java.lang.invoke.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A call target that replaces itself in the graph when being lowered by restoring the original + * {@link MethodHandle} invocation target. Prior to + * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a + * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In + * that case, the original invocation must be restored with all of its original arguments. Why? + * HotSpot linkage for {@link MethodHandle} intrinsics (see + * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be + * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo* + * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} + * invocation drops these arguments which means the interpreter won't find them. + */ +@NodeInfo +public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class); + + /** + * Creates a call target for an invocation on a direct target derived by resolving a constant + * {@link MethodHandle}. + */ + public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, + ValueNode[] originalArguments, JavaType originalReturnType) { + if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) { + // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60 + return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType); + } + return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType); + } + + protected final ResolvedJavaMethod originalTargetMethod; + protected final JavaType originalReturnType; + @Input NodeInputList originalArguments; + + protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, + ValueNode[] originalArguments, JavaType originalReturnType) { + super(TYPE, invokeKind, targetMethod, arguments, returnType); + this.originalTargetMethod = originalTargetMethod; + this.originalReturnType = originalReturnType; + this.originalArguments = new NodeInputList<>(this, originalArguments); + } + + @Override + public void lower(LoweringTool tool) { + InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special; + MethodCallTargetNode replacement = graph().add( + new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType)); + + // Replace myself... + this.replaceAndDelete(replacement); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + throw GraalInternalError.shouldNotReachHere("should have replaced itself"); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A helper class to allow elimination of byte code instrumentation that could interfere with escape + * analysis. + */ +@NodeInfo +public class VirtualizableInvokeMacroNode extends MacroStateSplitNode implements Virtualizable { + + public static final NodeClass TYPE = NodeClass.create(VirtualizableInvokeMacroNode.class); + + public VirtualizableInvokeMacroNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { + super(TYPE, invokeKind, targetMethod, bci, returnType, arguments); + } + + @Override + public void virtualize(VirtualizerTool tool) { + for (ValueNode arg : arguments) { + State state = tool.getObjectState(arg); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.delete(); + } + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu May 28 17:44:05 2015 +0200 @@ -74,7 +74,6 @@ return new HotSpotTruffleRuntime(); } - private TruffleCompilerImpl truffleCompiler; private Map> compilations = newIdentityMap(); private final ThreadPoolExecutor compileQueue; @@ -213,21 +212,12 @@ @Override public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) { if (truffleCompiler == null) { - truffleCompiler = new TruffleCompilerImpl(); + truffleCompiler = DefaultTruffleCompiler.create(); } Runnable r = new Runnable() { @Override public void run() { - boolean success = true; - try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) { - truffleCompiler.compileMethod(optimizedCallTarget); - } catch (Throwable e) { - optimizedCallTarget.notifyCompilationFailed(e); - success = false; - } finally { - optimizedCallTarget.notifyCompilationFinished(success); - - } + doCompile(optimizedCallTarget); } }; Future future = compileQueue.submit(r); @@ -306,7 +296,7 @@ } @Override - public boolean enableInfopoints() { + public boolean platformEnableInfopoints() { return HotSpotGraalRuntime.runtime().getCompilerToVM().shouldDebugNonSafepoints(); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/OptimizedCallTargetInstrumentation.java Thu May 28 17:44:05 2015 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.asm.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.framemap.*; @@ -48,7 +47,8 @@ @Override public Mark recordMark(Object id) { Mark mark = super.recordMark(id); - if (MarkId.getEnum((int) id) == MarkId.VERIFIED_ENTRY) { + HotSpotCodeCacheProvider hsCodeCache = (HotSpotCodeCacheProvider) codeCache; + if ((int) id == hsCodeCache.config.MARKID_VERIFIED_ENTRY) { HotSpotRegistersProvider registers = HotSpotGraalRuntime.runtime().getHostProviders().getRegisters(); injectTailCallCode(HotSpotGraalRuntime.runtime().getConfig(), registers); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java Thu May 28 17:44:05 2015 +0200 @@ -269,7 +269,7 @@ assertPartialEvalEqualsAndRunsCorrect(new Program("nestedLoopsProgram", bytecodes, 0, 6)); } - @Test(timeout = 1000) + @Test(timeout = 2000) public void manyIfsProgram() { byte[] bytecodes = new byte[]{ /* 0: */Bytecode.CONST, diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ConditionAnchoringTest.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2015, 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 @@ -38,6 +38,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.LoweringTool.StandardLoweringStage; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; @@ -147,7 +148,7 @@ private static final class InlineEverythingPlugin implements InlineInvokePlugin { public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { assert method.hasBytecodes(); - return new InlineInfo(method, false, false); + return new InlineInfo(method, false); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Thu May 28 17:44:05 2015 +0200 @@ -205,19 +205,19 @@ } @Test - public void constantValueInertToolEvalNodeFactory() { + public void constantValueInertAdvancedInstrumentRootFactory() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe testProbe = result.probe(); - // A factory that could insert a ToolEvalNode into the AST, but which never does. - Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { + // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does. + Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { - public ToolEvalNode createToolEvalNode(Probe probe, Node node) { + public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) { return null; } - }, null); + }, null, "test AdvancedInstrument"); testProbe.attach(instrument); // It all gets compiled away @@ -225,29 +225,30 @@ } @Test - public void constantValueInertToolEvalNode() { + public void constantValueInertAdvancedInstrumentRoot() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode resultTestNode = new ConstantTestNode(42); RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode); rootTestNode.adoptChildren(); Probe testProbe = resultTestNode.probe(); - // A factory that inserts a ToolEvalNode with empty methods into the instrumentation chain. - Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { + // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation . + Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { - public ToolEvalNode createToolEvalNode(Probe probe, Node node) { - return new ToolEvalNode() { + @Override + public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) { + return new AdvancedInstrumentRoot() { public String instrumentationInfo() { return null; } @Override - public Object executeToolEvalNode(Node n, VirtualFrame frame) { + public Object executeRoot(Node n, VirtualFrame frame) { return null; } }; } - }, null); + }, null, "test AdvancedInstrument"); testProbe.attach(instrument); // It all gets compiled away. @@ -351,6 +352,7 @@ final boolean[] isCurrentlyCompiled = {false}; final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() { + @Override public void notifyIsCompiled(boolean isCompiled) { isCurrentlyCompiled[0] = isCompiled; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Thu May 28 17:44:05 2015 +0200 @@ -38,12 +38,12 @@ import com.oracle.truffle.api.nodes.*; public class PartialEvaluationTest extends GraalCompilerTest { - private final TruffleCompilerImpl truffleCompiler; + private final TruffleCompiler truffleCompiler; public PartialEvaluationTest() { // Make sure Truffle runtime is initialized. Assert.assertTrue(Truffle.getRuntime() != null); - this.truffleCompiler = new TruffleCompilerImpl(); + this.truffleCompiler = DefaultTruffleCompiler.create(); DebugEnvironment.initialize(System.out); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Thu May 28 17:44:05 2015 +0200 @@ -28,8 +28,6 @@ public class CompilationProfile { - private static final int TIMESTAMP_THRESHOLD = Math.max(TruffleCompilationThreshold.getValue() / 2, 1); - /** * Number of times an installed code for this tree was invalidated. */ @@ -112,7 +110,7 @@ interpreterCallAndLoopCount++; int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; - if (callsMissing == TIMESTAMP_THRESHOLD) { + if (callsMissing == getTimestampThreshold()) { timestamp = System.nanoTime(); } } @@ -130,7 +128,7 @@ } public void deferCompilation() { - ensureProfiling(0, TIMESTAMP_THRESHOLD + 1); + ensureProfiling(0, getTimestampThreshold() + 1); timestamp = 0; deferedCount++; } @@ -139,7 +137,7 @@ interpreterCallAndLoopCount += count; int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; - if (callsMissing <= TIMESTAMP_THRESHOLD && callsMissing + count > TIMESTAMP_THRESHOLD) { + if (callsMissing <= getTimestampThreshold() && callsMissing + count > getTimestampThreshold()) { timestamp = System.nanoTime(); } } @@ -154,4 +152,7 @@ return timestamp; } + private static int getTimestampThreshold() { + return Math.max(TruffleCompilationThreshold.getValue() / 2, 1); + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2014, 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.truffle; + +import java.util.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.*; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.runtime.*; + +public final class DefaultTruffleCompiler extends TruffleCompiler { + + public static TruffleCompiler create() { + Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); + Suites suites = backend.getSuites().getDefaultSuites(); + LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites(); + GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); + Plugins plugins = phase.getGraphBuilderConfig().getPlugins(); + return new DefaultTruffleCompiler(plugins, suites, lirSuites, backend); + } + + private DefaultTruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) { + super(plugins, suites, lirSuites, backend); + } + + @Override + protected PartialEvaluator createPartialEvaluator() { + return new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch); + } + + @Override + protected PhaseSuite createGraphBuilderSuite() { + PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); + ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); + iterator.remove(); + iterator.add(new GraphBuilderPhase(config)); + return suite; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Thu May 28 17:44:05 2015 +0200 @@ -31,6 +31,8 @@ import com.oracle.graal.api.code.stack.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.debug.*; import com.oracle.graal.truffle.unsafe.*; @@ -55,7 +57,8 @@ private final List compilationListeners = new ArrayList<>(); private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener(); - private LoopNodeFactory loopNodeFactory; + protected TruffleCompiler truffleCompiler; + protected LoopNodeFactory loopNodeFactory; public GraalTruffleRuntime() { Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); @@ -101,11 +104,14 @@ if (!(repeatingNode instanceof Node)) { throw new IllegalArgumentException("Repeating node must be of type Node."); } + return getLoopNodeFactory().create(repeatingNode); + } + + protected LoopNodeFactory getLoopNodeFactory() { if (loopNodeFactory == null) { loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class); } - - return loopNodeFactory.create(repeatingNode); + return loopNodeFactory; } @Override @@ -271,6 +277,18 @@ public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous); + protected void doCompile(OptimizedCallTarget optimizedCallTarget) { + boolean success = true; + try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) { + truffleCompiler.compileMethod(optimizedCallTarget); + } catch (Throwable e) { + optimizedCallTarget.notifyCompilationFailed(e); + success = false; + } finally { + optimizedCallTarget.notifyCompilationFinished(success); + } + } + public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason); public abstract void waitForCompilation(OptimizedCallTarget optimizedCallTarget, long timeout) throws ExecutionException, TimeoutException; @@ -281,7 +299,12 @@ public abstract void reinstallStubs(); - public abstract boolean enableInfopoints(); + public final boolean enableInfopoints() { + /* Currently infopoints can change code generation so don't enable them automatically */ + return platformEnableInfopoints() && TruffleEnableInfopoints.getValue(); + } + + protected abstract boolean platformEnableInfopoints(); private final class DispatchTruffleCompilationListener implements GraalTruffleCompilationListener { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java Thu May 28 17:44:05 2015 +0200 @@ -28,8 +28,6 @@ public final class OptimizedOSRLoopNode extends LoopNode implements ReplaceObserver { - private static final int OSR_THRESHOLD = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue(); - private int interpreterLoopCount; private OptimizedCallTarget compiledTarget; @@ -75,7 +73,8 @@ } private boolean profilingLoop(VirtualFrame frame) { - int overflowLoopCount = Integer.MAX_VALUE - OSR_THRESHOLD + interpreterLoopCount; + int osrThreshold = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue(); + int overflowLoopCount = Integer.MAX_VALUE - osrThreshold + interpreterLoopCount; try { while (repeatableNode.executeRepeating(frame)) { try { @@ -86,7 +85,7 @@ } } } finally { - reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + OSR_THRESHOLD - interpreterLoopCount); + reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + osrThreshold - interpreterLoopCount); } return true; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu May 28 17:44:05 2015 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.truffle; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.truffle.TruffleCompilerOptions.*; import java.lang.invoke.*; @@ -71,8 +71,8 @@ @Option(help = "New partial evaluation on Graal graphs", type = OptionType.Expert)// public static final StableOptionValue GraphPE = new StableOptionValue<>(true); - private final Providers providers; - private final Architecture architecture; + protected final Providers providers; + protected final Architecture architecture; private final CanonicalizerPhase canonicalizer; private final SnippetReflectionProvider snippetReflection; private final ResolvedJavaMethod callDirectMethod; @@ -140,11 +140,6 @@ } public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) { - if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) { - ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true)); - builder.addPush(trueNode); - return true; - } return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null); } } @@ -190,7 +185,7 @@ if (replacements.hasSubstitution(original, builder.bci())) { return null; } - assert !builder.parsingReplacement(); + assert !builder.parsingIntrinsic(); if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { if (original.equals(callSiteProxyMethod)) { @@ -210,12 +205,12 @@ if (decision != null && decision.isInline()) { inlining.push(decision); builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption())); - return new InlineInfo(callInlinedMethod, false, false); + return new InlineInfo(callInlinedMethod, false); } } } - return new InlineInfo(original, false, false); + return new InlineInfo(original, false); } @Override @@ -277,10 +272,10 @@ * We want to inline invokes that have a constant MethodHandle parameter to remove * invokedynamic related calls as early as possible. */ - return new InlineInfo(original, false, false); + return new InlineInfo(original, false); } if (inlineDuringParsing && original.hasBytecodes() && original.getCode().length < TrivialInliningSize.getValue() && builder.getDepth() < InlineDuringParsingMaxDepth.getValue()) { - return new InlineInfo(original, false, false); + return new InlineInfo(original, false); } return null; } @@ -319,19 +314,17 @@ } plugins.setInlineInvokePlugin(inlinePlugin); plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin()); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompiler.Optimizations, null).apply(graph); if (PrintTruffleExpansionHistogram.getValue()) { ((HistogramInlineInvokePlugin) inlinePlugin).print(callTarget, System.out); } } - protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) { + protected PEGraphDecoder createGraphDecoder(StructuredGraph graph) { GraphBuilderConfiguration newConfig = configForRoot.copy(); InvocationPlugins parsingInvocationPlugins = newConfig.getPlugins().getInvocationPlugins(); TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), parsingInvocationPlugins, true, snippetReflection); - callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); - LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin(); newConfig.setUseProfiling(false); @@ -340,12 +333,18 @@ plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue())); - CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + return new CachingPEGraphDecoder(providers, newConfig, TruffleCompiler.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + } + protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) { + callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); + + PEGraphDecoder decoder = createGraphDecoder(graph); + + LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin(); ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget); - InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess()); - TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection); + InvocationPlugins decodingInvocationPlugins = createDecodingInvocationPlugins(); InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements()); if (PrintTruffleExpansionHistogram.getValue()) { decodingInlinePlugin = new HistogramInlineInvokePlugin(graph, decodingInlinePlugin); @@ -358,6 +357,12 @@ } } + protected InvocationPlugins createDecodingInvocationPlugins() { + InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess()); + TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection); + return decodingInvocationPlugins; + } + @SuppressWarnings("unused") private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { if (GraphPE.getValue()) { @@ -434,13 +439,13 @@ } public StructuredGraph createRootGraph(StructuredGraph graph) { - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph); return graph; } public StructuredGraph createInlineGraph(String name, StructuredGraph caller) { StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null)); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph); return graph; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2013, 2014, 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.truffle; + +import static com.oracle.graal.api.code.CodeUtil.*; +import static com.oracle.graal.compiler.GraalCompiler.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.Assumptions.Assumption; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.printer.*; +import com.oracle.graal.truffle.nodes.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Implementation of the Truffle compiler using Graal. + */ +public abstract class TruffleCompiler { + + protected final Providers providers; + protected final Suites suites; + protected final GraphBuilderConfiguration config; + protected final LIRSuites lirSuites; + protected final PartialEvaluator partialEvaluator; + protected final Backend backend; + protected final GraalTruffleCompilationListener compilationNotify; + + // @formatter:off + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{ + UnexpectedResultException.class, + SlowPathException.class, + ArithmeticException.class, + IllegalArgumentException.class, + VirtualMachineError.class, + StringIndexOutOfBoundsException.class, + ClassCastException.class + }; + // @formatter:on + + public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, + OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); + + public TruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) { + GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime()); + this.compilationNotify = graalTruffleRuntime.getCompilationNotify(); + this.backend = backend; + Providers backendProviders = backend.getProviders(); + ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess()); + this.providers = backendProviders.copyWith(constantReflection); + this.suites = suites; + this.lirSuites = lirSuites; + + ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); + + GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(new Plugins(plugins)) + : GraphBuilderConfiguration.getDefault(new Plugins(plugins)); + this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes).withOmitAssertions(TruffleCompilerOptions.TruffleExcludeAssertions.getValue()); + + this.partialEvaluator = createPartialEvaluator(); + + if (Debug.isEnabled()) { + DebugEnvironment.initialize(System.out); + } + } + + protected abstract PartialEvaluator createPartialEvaluator(); + + public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; + for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { + skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); + } + return skippedExceptionTypes; + } + + public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime"); + public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); + + public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse"); + public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse"); + public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse"); + + public void compileMethod(final OptimizedCallTarget compilable) { + StructuredGraph graph = null; + + compilationNotify.notifyCompilationStarted(compilable); + + try { + PhaseSuite graphBuilderSuite = createGraphBuilderSuite(); + + try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) { + graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES); + } + + if (Thread.currentThread().isInterrupted()) { + return; + } + + compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph); + CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable); + compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult); + } catch (Throwable t) { + System.out.println("compilation failed!?"); + compilationNotify.notifyCompilationFailed(compilable, graph, t); + throw t; + } + } + + public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) { + try (Scope s = Debug.scope("TruffleFinal")) { + Debug.dump(1, graph, "After TruffleTier"); + } catch (Throwable e) { + throw Debug.handle(e); + } + + CompilationResult result = null; + try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) { + CodeCacheProvider codeCache = providers.getCodeCache(); + CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); + CompilationResult compilationResult = new CompilationResult(name); + result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, + compilationResult, CompilationResultBuilderFactory.Default); + } catch (Throwable e) { + throw Debug.handle(e); + } + + compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph); + + if (graph.isInlinedMethodRecordingEnabled()) { + result.setMethods(graph.method(), graph.getInlinedMethods()); + } else { + assert result.getMethods() == null; + } + + List validAssumptions = new ArrayList<>(); + Set newAssumptions = new HashSet<>(); + for (Assumption assumption : graph.getAssumptions()) { + processAssumption(newAssumptions, assumption, validAssumptions); + } + + if (result.getAssumptions() != null) { + for (Assumption assumption : result.getAssumptions()) { + processAssumption(newAssumptions, assumption, validAssumptions); + } + } + + result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); + + InstalledCode installedCode; + try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) { + installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode); + } catch (Throwable e) { + throw Debug.handle(e); + } + + for (AssumptionValidAssumption a : validAssumptions) { + a.getAssumption().registerInstalledCode(installedCode); + } + + if (Debug.isLogEnabled()) { + Debug.log(providers.getCodeCache().disassemble(result, installedCode)); + } + return result; + } + + protected abstract PhaseSuite createGraphBuilderSuite(); + + public void processAssumption(Set newAssumptions, Assumption assumption, List manual) { + if (assumption != null) { + if (assumption instanceof AssumptionValidAssumption) { + AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption; + manual.add(assumptionValidAssumption); + } else { + newAssumptions.add(assumption); + } + } + } + + public PartialEvaluator getPartialEvaluator() { + return partialEvaluator; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2013, 2014, 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.truffle; - -import static com.oracle.graal.api.code.CodeUtil.*; -import static com.oracle.graal.compiler.GraalCompiler.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.meta.Assumptions.Assumption; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import com.oracle.graal.java.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.lir.phases.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.printer.*; -import com.oracle.graal.runtime.*; -import com.oracle.graal.truffle.nodes.*; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Implementation of the Truffle compiler using Graal. - */ -public class TruffleCompilerImpl { - - private final Providers providers; - private final Suites suites; - private final LIRSuites lirSuites; - private final PartialEvaluator partialEvaluator; - private final Backend backend; - private final GraphBuilderConfiguration config; - private final RuntimeProvider runtime; - private final GraalTruffleCompilationListener compilationNotify; - - // @formatter:off - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{ - UnexpectedResultException.class, - SlowPathException.class, - ArithmeticException.class, - IllegalArgumentException.class, - VirtualMachineError.class, - StringIndexOutOfBoundsException.class, - ClassCastException.class - }; - // @formatter:on - - public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, - OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); - - public TruffleCompilerImpl() { - GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime()); - this.runtime = Graal.getRequiredCapability(RuntimeProvider.class); - this.compilationNotify = graalTruffleRuntime.getCompilationNotify(); - this.backend = runtime.getHostBackend(); - Providers backendProviders = backend.getProviders(); - ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess()); - this.providers = backendProviders.copyWith(constantReflection); - this.suites = backend.getSuites().getDefaultSuites(); - this.lirSuites = backend.getSuites().getDefaultLIRSuites(); - - ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); - - GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); - // copy all plugins from the host - Plugins plugins = new Plugins(phase.getGraphBuilderConfig().getPlugins()); - GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(plugins) : GraphBuilderConfiguration.getDefault(plugins); - this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes); - - this.partialEvaluator = new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch); - - if (Debug.isEnabled()) { - DebugEnvironment.initialize(System.out); - } - } - - public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { - ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; - for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { - skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); - } - return skippedExceptionTypes; - } - - public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime"); - public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); - public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); - - public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse"); - public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse"); - public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse"); - - public void compileMethod(final OptimizedCallTarget compilable) { - StructuredGraph graph = null; - - compilationNotify.notifyCompilationStarted(compilable); - - try { - PhaseSuite graphBuilderSuite = createGraphBuilderSuite(); - - try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) { - graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES); - } - - if (Thread.currentThread().isInterrupted()) { - return; - } - - compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph); - CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable); - compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult); - } catch (Throwable t) { - System.out.println("compilation failed!?"); - compilationNotify.notifyCompilationFailed(compilable, graph, t); - throw t; - } - } - - public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) { - try (Scope s = Debug.scope("TruffleFinal")) { - Debug.dump(1, graph, "After TruffleTier"); - } catch (Throwable e) { - throw Debug.handle(e); - } - - CompilationResult result = null; - try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) { - CodeCacheProvider codeCache = providers.getCodeCache(); - CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); - CompilationResult compilationResult = new CompilationResult(name); - result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, - compilationResult, CompilationResultBuilderFactory.Default); - } catch (Throwable e) { - throw Debug.handle(e); - } - - compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph); - - if (graph.isInlinedMethodRecordingEnabled()) { - result.setMethods(graph.method(), graph.getInlinedMethods()); - } else { - assert result.getMethods() == null; - } - - List validAssumptions = new ArrayList<>(); - Set newAssumptions = new HashSet<>(); - for (Assumption assumption : graph.getAssumptions()) { - processAssumption(newAssumptions, assumption, validAssumptions); - } - - if (result.getAssumptions() != null) { - for (Assumption assumption : result.getAssumptions()) { - processAssumption(newAssumptions, assumption, validAssumptions); - } - } - - result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); - - InstalledCode installedCode; - try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) { - installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode); - } catch (Throwable e) { - throw Debug.handle(e); - } - - for (AssumptionValidAssumption a : validAssumptions) { - a.getAssumption().registerInstalledCode(installedCode); - } - - if (Debug.isLogEnabled()) { - Debug.log(providers.getCodeCache().disassemble(result, installedCode)); - } - return result; - } - - private PhaseSuite createGraphBuilderSuite() { - PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); - ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); - iterator.remove(); - iterator.add(new GraphBuilderPhase(config)); - return suite; - } - - public void processAssumption(Set newAssumptions, Assumption assumption, List manual) { - if (assumption != null) { - if (assumption instanceof AssumptionValidAssumption) { - AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption; - manual.add(assumptionValidAssumption); - } else { - newAssumptions.add(assumption); - } - } - } - - public PartialEvaluator getPartialEvaluator() { - return partialEvaluator; - } -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu May 28 17:44:05 2015 +0200 @@ -170,5 +170,8 @@ @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.", type = OptionType.Debug) public static final OptionValue TruffleCompilationStatisticDetails = new OptionValue<>(false); + + @Option(help = "Enable support for simple infopoints in truffle partial evaluations.", type = OptionType.Expert) + public static final OptionValue TruffleEnableInfopoints = new OptionValue<>(false); // @formatter:on } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java Thu May 28 17:44:05 2015 +0200 @@ -52,6 +52,10 @@ return graalConstantReflection.readConstantArrayElement(array, index); } + public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) { + return graalConstantReflection.readConstantArrayElementForOffset(array, offset); + } + public JavaConstant readConstantFieldValue(JavaField field0, JavaConstant receiver) { ResolvedJavaField field = (ResolvedJavaField) field0; if (!field.isStatic() && receiver.isNonNull()) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java Thu May 28 17:44:05 2015 +0200 @@ -27,8 +27,6 @@ public final class AssumptionValidAssumption extends Assumptions.Assumption { - private static final long serialVersionUID = 2010244979610891262L; - private final OptimizedAssumption assumption; public AssumptionValidAssumption(OptimizedAssumption assumption) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Thu May 28 17:44:05 2015 +0200 @@ -53,11 +53,15 @@ } private ObjectLocationIdentity(JavaConstant object) { - super(false); this.object = object; } @Override + public boolean isImmutable() { + return false; + } + + @Override public String toString() { return "Identity(" + object + ")"; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Thu May 28 17:44:05 2015 +0200 @@ -34,8 +34,8 @@ public static final NodeClass TYPE = NodeClass.create(NeverPartOfCompilationNode.class); protected final String message; - public NeverPartOfCompilationNode(String message, FrameState stateAfter) { - super(TYPE, StampFactory.forVoid(), stateAfter); + public NeverPartOfCompilationNode(String message) { + super(TYPE, StampFactory.forVoid()); this.message = message; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Thu May 28 17:44:05 2015 +0200 @@ -239,7 +239,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { String messageString = message.asConstant().toValueString(); - b.add(new NeverPartOfCompilationNode(messageString, b.createStateAfter())); + b.add(new NeverPartOfCompilationNode(messageString)); return true; } else if (canDelayIntrinsification) { return false; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Thu May 28 17:44:05 2015 +0200 @@ -182,7 +182,7 @@ /** * Collects the effects of virtualizing the given node. - * + * * @return {@code true} if the effects include removing the node, {@code false} otherwise. */ protected abstract boolean processNode(Node node, BlockT state, GraphEffectList effects, FixedWithNextNode lastFixedNode); @@ -210,6 +210,7 @@ BlockT loopEntryState = initialState; BlockT lastMergedState = cloneState(initialState); + processInitialLoopState(loop, lastMergedState); MergeProcessor mergeProcessor = createMergeProcessor(loop.getHeader()); for (int iteration = 0; iteration < 10; iteration++) { LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, cloneState(lastMergedState)); @@ -245,6 +246,11 @@ throw new GraalInternalError("too many iterations at %s", loop); } + @SuppressWarnings("unused") + protected void processInitialLoopState(Loop loop, BlockT initialState) { + // nothing to do + } + private void doMergeWithoutDead(MergeProcessor mergeProcessor, List states) { int alive = 0; for (BlockT state : states) { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Thu May 28 17:44:05 2015 +0200 @@ -115,7 +115,7 @@ ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { - assert !obj.isVirtual(); + assert !obj.isVirtual() : object; cacheObject = obj.getMaterializedValue(); } else { cacheObject = object; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -27,11 +27,13 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; @@ -212,6 +214,23 @@ } @Override + protected void processInitialLoopState(Loop loop, PEReadEliminationBlockState initialState) { + super.processInitialLoopState(loop, initialState); + + for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { + ValueNode firstValue = phi.valueAt(0); + if (firstValue != null) { + firstValue = GraphUtil.unproxify(firstValue); + for (Map.Entry entry : new ArrayList<>(initialState.getReadCache().entrySet())) { + if (entry.getKey().object == firstValue) { + initialState.addReadCache(phi, entry.getKey().identity, entry.getKey().index, entry.getValue(), this); + } + } + } + } + } + + @Override protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) { super.processLoopExit(exitNode, initialState, exitState, effects); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu May 28 17:44:05 2015 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; @@ -135,15 +136,21 @@ FixedNode nextFixedNode = lastFixedNode == null ? null : lastFixedNode.next(); VirtualUtil.trace("%s", node); - if (node instanceof VirtualizableAllocation) { - if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) { + if (requiresProcessing(node)) { + if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) { + return false; + } + if (tool.isDeleted()) { VirtualUtil.trace("deleted virtualizable allocation %s", node); return true; } } if (hasVirtualInputs.isMarked(node) && node instanceof ValueNode) { if (node instanceof Virtualizable) { - if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects)) { + if (processVirtualizable((ValueNode) node, nextFixedNode, state, effects) == false) { + return false; + } + if (tool.isDeleted()) { VirtualUtil.trace("deleted virtualizable node %s", node); return true; } @@ -159,6 +166,10 @@ return false; } + protected boolean requiresProcessing(Node node) { + return node instanceof VirtualizableAllocation; + } + private boolean processNodeWithScalarReplacedInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) { ValueNode canonicalizedValue = node; if (node instanceof Canonicalizable.Unary) { @@ -264,8 +275,12 @@ private boolean processVirtualizable(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) { tool.reset(state, node, insertBefore, effects); - ((Virtualizable) node).virtualize(tool); - return tool.isDeleted(); + return virtualize(node, tool); + } + + protected boolean virtualize(ValueNode node, VirtualizerTool vt) { + ((Virtualizable) node).virtualize(vt); + return true; // request further processing } private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) { @@ -359,6 +374,20 @@ } @Override + protected void processInitialLoopState(Loop loop, BlockT initialState) { + super.processInitialLoopState(loop, initialState); + + for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { + if (phi.valueAt(0) != null) { + ObjectState state = getObjectState(initialState, phi.valueAt(0)); + if (state != null && state.isVirtual()) { + addAndMarkAlias(state.virtual, phi); + } + } + } + } + + @Override protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) { if (exitNode.graph().hasValueProxies()) { Map proxies = Node.newMap(); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Thu May 28 17:44:05 2015 +0200 @@ -109,6 +109,12 @@ return success; } + public static void trace(String format) { + if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format); + } + } + public static void trace(String format, Object obj) { if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { Debug.logv(format, obj); @@ -127,6 +133,12 @@ } } + public static void trace(String format, Object obj, Object obj2, Object obj3, Object obj4) { + if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format, obj, obj2, obj3, obj4); + } + } + public static boolean matches(StructuredGraph graph, String filter) { if (filter != null) { return matchesHelper(graph, filter); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -23,8 +23,8 @@ package com.oracle.graal.word; import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; /** * Lowest-level memory access of native C memory. These methods access the raw memory without any diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -30,9 +30,9 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.memory.HeapAccess.*; public abstract class Word implements Signed, Unsigned, Pointer { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 2015, 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.dsl.test; + +import java.lang.annotation.*; + +/** + * This annotation is internally known by the dsl processor and used to expect errors for testing + * purposes. This is not part of public API. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ExpectError { + + String[] value(); + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java Thu May 28 17:44:05 2015 +0200 @@ -105,7 +105,6 @@ } @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"}) - @ExplodeLoop double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) { doPowCachedExponent++; double result = 1.0; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/Compile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/Compile.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014, 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.dsl.test.processor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import static org.junit.Assert.*; + +final class Compile implements DiagnosticListener { + private final List> errors = new ArrayList<>(); + private final Map classes; + private final String sourceLevel; + + private Compile(Class processor, String code, String sl) { + this.sourceLevel = sl; + classes = compile(processor, code); + } + + /** + * Performs compilation of given HTML page and associated Java code. + */ + public static Compile create(Class processor, String code) { + return new Compile(processor, code, "1.7"); + } + + /** Checks for given class among compiled resources. */ + public byte[] get(String res) { + return classes.get(res); + } + + /** + * Obtains errors created during compilation. + */ + public List> getErrors() { + List> err; + err = new ArrayList<>(); + for (Diagnostic diagnostic : errors) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + err.add(diagnostic); + } + } + return err; + } + + private Map compile(Class processor, final String code) { + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); + + final Map class2BAOS; + class2BAOS = new HashMap<>(); + + JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } + }; + + JavaFileManager jfm = new ForwardingJavaFileManager(sjfm) { + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + if (kind == Kind.CLASS) { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + class2BAOS.put(className.replace('.', '/') + ".class", buffer); + return new SimpleJavaFileObject(sibling.toUri(), kind) { + @Override + public OutputStream openOutputStream() { + return buffer; + } + }; + } + + if (kind == Kind.SOURCE) { + final String n = className.replace('.', '/') + ".java"; + final URI un; + try { + un = new URI("mem://" + n); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + return new VirtFO(un/* sibling.toUri() */, kind, n); + } + + throw new IllegalStateException(); + } + + @Override + public boolean isSameFile(FileObject a, FileObject b) { + if (a instanceof VirtFO && b instanceof VirtFO) { + return ((VirtFO) a).getName().equals(((VirtFO) b).getName()); + } + + return super.isSameFile(a, b); + } + + class VirtFO extends SimpleJavaFileObject { + + private final String n; + + public VirtFO(URI uri, Kind kind, String n) { + super(uri, kind); + this.n = n; + } + + private final ByteArrayOutputStream data = new ByteArrayOutputStream(); + + @Override + public OutputStream openOutputStream() { + return data; + } + + @Override + public String getName() { + return n; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + data.close(); + return new String(data.toByteArray()); + } + } + }; + List args = Arrays.asList("-source", sourceLevel, "-target", "1.7", // + "-processor", processor.getName()); + + ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, args, null, Arrays.asList(file)).call(); + + Map result = new HashMap<>(); + + for (Map.Entry e : class2BAOS.entrySet()) { + result.put(e.getKey(), e.getValue().toByteArray()); + } + + return result; + } + + @Override + public void report(Diagnostic diagnostic) { + errors.add(diagnostic); + } + + void assertErrors() { + assertFalse("There are supposed to be some errors", getErrors().isEmpty()); + } + + void assertNoErrors() { + assertTrue("There are supposed to be no errors: " + getErrors(), getErrors().isEmpty()); + } + + void assertError(String expMsg) { + StringBuilder sb = new StringBuilder(); + sb.append("Can't find ").append(expMsg).append(" among:"); + for (Diagnostic e : errors) { + String msg = e.getMessage(Locale.US); + if (msg.contains(expMsg)) { + return; + } + sb.append("\n"); + sb.append(msg); + } + fail(sb.toString()); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, 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.dsl.test.processor; + +import java.io.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.test.*; +import com.oracle.truffle.api.source.*; + +public class LanguageRegistrationTest { + + @ExpectError("Registered language class must be public") + @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my") + private static final class MyLang { + } + + @ExpectError("Registered language inner-class must be static") + @TruffleLanguage.Registration(name = "myLangNonStatic", mimeType = "text/x-my") + public final class MyLangNonStatic { + } + + @ExpectError("Registered language class must subclass TruffleLanguage") + @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my") + public static final class MyLangNoSubclass { + } + + @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter") + @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my") + public static final class MyLangWrongConstr extends TruffleLanguage { + private MyLangWrongConstr() { + super(null); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } + + @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter") + @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my") + public static final class MyLangNoConstr extends TruffleLanguage { + public MyLangNoConstr() { + super(null); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } + + @TruffleLanguage.Registration(name = "myLangGood", mimeType = "text/x-my") + public static final class MyLangGood extends TruffleLanguage { + public MyLangGood(TruffleLanguage.Env env) { + super(env); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014, 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.dsl.test.processor; + +import static org.junit.Assert.*; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.tools.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.test.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.verify.*; + +/** + * Verify errors emitted by the processor. + */ +public class TruffleProcessorTest { + // + // AnnotationProcessor test using the NetBeans style + // + + @Test + public void childCannotBeFinal() throws Exception { + // @formatter:off + String code = "package x.y.z;\n" + + "import com.oracle.truffle.api.nodes.Node;\n" + + "abstract class MyNode extends Node {\n" + + " @Child final MyNode first;\n" + + " MyNode(MyNode n) {\n" + + " this.first = n;\n" + + " };\n" + + "}\n"; + // @formatter:on + + Compile c = Compile.create(VerifyTruffleProcessor.class, code); + c.assertErrors(); + boolean ok = false; + StringBuilder msgs = new StringBuilder(); + for (Diagnostic e : c.getErrors()) { + String msg = e.getMessage(Locale.ENGLISH); + if (msg.contains("cannot be final")) { + ok = true; + } + msgs.append("\n").append(msg); + } + if (!ok) { + fail("Should contain warning about final:" + msgs); + } + } + + @Test + public void workAroundCannonicalDependency() throws Exception { + Class myProc = VerifyTruffleProcessor.class; + assertNotNull(myProc); + StringBuilder sb = new StringBuilder(); + sb.append("Cannot find ").append(myProc); + for (Processor load : ServiceLoader.load(Processor.class)) { + sb.append("Found ").append(load); + if (myProc.isInstance(load)) { + return; + } + } + fail(sb.toString()); + } + + // + // and now the Truffle traditional way + // + + abstract class MyNode extends Node { + @ExpectError("@Child field cannot be final") @Child final MyNode first; + + MyNode(MyNode n) { + this.first = n; + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2012, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.dsl; - -import java.lang.annotation.*; - -/** - * This annotation is internally known by the dsl processor and used to expect errors for testing - * purposes. This is not part of public API. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface ExpectError { - - String[] value(); - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.test.instrument; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdvancedInstrumentCounterRoot; + +/** + * Tests the kind of instrumentation where a client can provide an AST fragment to be + * spliced directly into the AST. + */ +public class AdvancedInstrumentTest { + + @Test + public void testAdvancedInstrumentListener() { + // Create a simple addition AST + final TruffleRuntime runtime = Truffle.getRuntime(); + final TestValueNode leftValueNode = new TestValueNode(6); + final TestValueNode rightValueNode = new TestValueNode(7); + final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); + final TestRootNode rootNode = new TestRootNode(addNode); + final CallTarget callTarget1 = runtime.createCallTarget(rootNode); + + // Ensure it executes correctly + assertEquals(13, callTarget1.call()); + + // Probe the addition node + final Probe probe = addNode.probe(); + + assertEquals(13, callTarget1.call()); + + // Attach a null factory; it never actually attaches a node. + final Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { + + public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) { + return null; + } + }, null, "test AdvancedInstrument"); + probe.attach(instrument); + + assertEquals(13, callTarget1.call()); + + final TestAdvancedInstrumentCounterRoot counter = new TestAdvancedInstrumentCounterRoot(); + + // Attach a factory that splices an execution counter into the AST. + probe.attach(Instrument.create(null, new AdvancedInstrumentRootFactory() { + + public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) { + return counter; + } + }, null, "test AdvancedInstrument")); + assertEquals(0, counter.getCount()); + + assertEquals(13, callTarget1.call()); + + assertEquals(1, counter.getCount()); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Thu May 28 17:44:05 2015 +0200 @@ -167,12 +167,12 @@ } } - static class TestToolEvalCounterNode extends ToolEvalNode { + static class TestAdvancedInstrumentCounterRoot extends AdvancedInstrumentRoot { private long count; @Override - public Object executeToolEvalNode(Node node, VirtualFrame vFrame) { + public Object executeRoot(Node node, VirtualFrame vFrame) { count++; return null; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2015, 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.test.instrument; - -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestToolEvalCounterNode; - -/** - * Tests the kind of instrumentation where a client can provide an AST fragment to be - * spliced directly into the AST. - */ -public class ToolEvalInstrumentTest { - - @Test - public void testSpliceInstrumentListener() { - // Create a simple addition AST - final TruffleRuntime runtime = Truffle.getRuntime(); - final TestValueNode leftValueNode = new TestValueNode(6); - final TestValueNode rightValueNode = new TestValueNode(7); - final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); - final CallTarget callTarget1 = runtime.createCallTarget(rootNode); - - // Ensure it executes correctly - assertEquals(13, callTarget1.call()); - - // Probe the addition node - final Probe probe = addNode.probe(); - - assertEquals(13, callTarget1.call()); - - // Attach a null listener; it never actually attaches a node. - final Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { - - public ToolEvalNode createToolEvalNode(Probe p, Node n) { - return null; - } - }, null); - probe.attach(instrument); - - assertEquals(13, callTarget1.call()); - - final TestToolEvalCounterNode counter = new TestToolEvalCounterNode(); - - // Attach a listener that splices an execution counter into the AST. - probe.attach(Instrument.create(new ToolEvalNodeFactory() { - - public ToolEvalNode createToolEvalNode(Probe p, Node n) { - return counter; - } - }, null)); - assertEquals(0, counter.getCount()); - - assertEquals(13, callTarget1.call()); - - assertEquals(1, counter.getCount()); - - } - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012, 2015, 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.test.vm; + +import com.oracle.truffle.api.vm.TruffleVM; +import java.util.Random; +import org.junit.Test; + +/** + * A collection of tests that can certify language implementaiton to be complient with most recent + * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and + * include in your test suite. + */ +public class TruffleTCK { // abstract + private TruffleVM tckVM; + + public TruffleTCK() { // protected + } + + /** + * This methods is called before first test is executed. It's purpose is to set a TruffleVM with + * your language up, so it is ready for testing. + * {@link TruffleVM#eval(java.lang.String, java.lang.String) Execute} any scripts you need, and + * prepare global symbols with proper names. The symbols will then be looked up by the + * infastructure (using the names provided by you from methods like {@link #plusInt()}) and used + * for internal testing. + * + * @return initialized Truffle virtual machine + * @throws java.lang.Exception thrown when the VM preparation fails + */ + protected TruffleVM prepareVM() throws Exception { // abstract + return null; + } + + /** + * Name of function which will return value 42 as a number. The return value of the method + * should be instance of {@link Number} and its {@link Number#intValue()} should return + * 42. + * + * @return name of globally exported symbol + */ + protected String fourtyTwo() { // abstract + return null; + } + + /** + * Name of function to add two integer values together. The symbol will be invoked with two + * parameters of type {@link Integer} and expects result of type {@link Number} which's + * {@link Number#intValue()} is equivalent of param1 + param2. + * + * @return name of globally exported symbol + */ + protected String plusInt() { // abstract + return null; + } + + private TruffleVM vm() throws Exception { + if (tckVM == null) { + tckVM = prepareVM(); + } + return tckVM; + } + + // + // The tests + // + + @Test + public void testFortyTwo() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } + TruffleVM.Symbol fourtyTwo = findGlobalSymbol(fourtyTwo()); + + Object res = fourtyTwo.invoke(null); + + assert res instanceof Number : "should yield a number, but was: " + res; + + Number n = (Number) res; + + assert 42 == n.intValue() : "The value is 42 = " + n.intValue(); + } + + @Test + public void testPlusWithInts() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } + Random r = new Random(); + int a = r.nextInt(100); + int b = r.nextInt(100); + + TruffleVM.Symbol plus = findGlobalSymbol(plusInt()); + + Object res = plus.invoke(null, a, b); + + assert res instanceof Number : "+ on two ints should yield a number, but was: " + res; + + Number n = (Number) res; + + assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") = " + n.intValue(); + } + + private TruffleVM.Symbol findGlobalSymbol(String name) throws Exception { + TruffleVM.Symbol s = vm().findGlobalSymbol(name); + assert s != null : "Symbol " + name + " is not found!"; + return s; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, 2015, 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.test.vm; + +import com.oracle.truffle.api.vm.TruffleVM; +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import org.junit.Before; +import org.junit.Test; + +public class TruffleVMSingleThreadedTest { + TruffleVM tvm; + + @Before + public void initInDifferentThread() throws InterruptedException { + final TruffleVM.Builder b = TruffleVM.newVM(); + Thread t = new Thread("Initializer") { + @Override + public void run() { + tvm = b.build(); + } + }; + t.start(); + t.join(); + } + + @Test(expected = IllegalStateException.class) + public void evalURI() throws IOException, URISyntaxException { + tvm.eval(new URI("http://unknown.js")); + } + + @Test(expected = IllegalStateException.class) + public void evalString() throws IOException { + tvm.eval("text/javascript", "1 + 1"); + } + + @Test(expected = IllegalStateException.class) + public void evalReader() throws IOException { + try (StringReader sr = new StringReader("1 + 1")) { + tvm.eval("text/javascript", sr); + } + } + + @Test(expected = IllegalStateException.class) + public void findGlobalSymbol() { + tvm.findGlobalSymbol("doesNotExists"); + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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; + +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.api.vm.TruffleVM.Language; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; + +/** + * An entry point for everyone who wants to implement a Truffle based language. By providing + * implementation of this type and registering it using {@link Registration} annotation, your + * language becomes accessible to users of the {@link TruffleVM Truffle virtual machine} - all they + * will need to do is to include your JAR into their application and all the Truffle goodies (multi + * language support, multi tennat hosting, debugging, etc.) will be made available to them. + */ +public abstract class TruffleLanguage { + private final Env env; + + /** + * Constructor to be called by subclasses. + * + * @param env language environment that will be available via {@link #env()} method to + * subclasses. + */ + protected TruffleLanguage(Env env) { + this.env = env; + } + + /** + * The annotation to use to register your language to the {@link TruffleVM Truffle} system. By + * annotating your implementation of {@link TruffleLanguage} by this annotation you are just a + * one JAR drop to the classpath away from your users. Once they include your JAR in + * their application, your language will be available to the {@link TruffleVM Truffle virtual + * machine}. + */ + @Retention(RetentionPolicy.SOURCE) + @Target(ElementType.TYPE) + public @interface Registration { + /** + * Unique name of your language. This name will be exposed to users via the + * {@link Language#getName()} getter. + * + * @return identifier of your language + */ + String name(); + + /** + * List of mimetypes associated with your language. Users will use them (directly or + * inderectly) when {@link TruffleVM#eval(java.lang.String, java.lang.String) executing} + * their code snippets or their {@link TruffleVM#eval(java.net.URI) files}. + * + * @return array of mime types assigned to your language files + */ + String[] mimeType(); + } + + protected final Env env() { + if (this.env == null) { + throw new NullPointerException("Accessing env before initialization is finished"); + } + return this.env; + } + + protected abstract Object eval(Source code) throws IOException; + + /** + * Called when some other language is seeking for a global symbol. This method is supposed to do + * lazy binding, e.g. there is no need to export symbols in advance, it is fine to wait until + * somebody asks for it (by calling this method). + *

    + * The exported object can either be TruffleObject (e.g. a native object from the + * other language) to support interoperability between languages or one of Java primitive + * wrappers ( {@link Integer}, {@link Double}, {@link Short}, etc.). + * + * @param globalName the name of the global symbol to find + * @return an exported object or null, if the symbol does not represent anything + * meaningful in this language + */ + protected abstract Object findExportedSymbol(String globalName); + + /** + * Returns global object for the language. + *

    + * The object is expected to be TruffleObject (e.g. a native object from the other + * language) but technically it can be one of Java primitive wrappers ({@link Integer}, + * {@link Double}, {@link Short}, etc.). + * + * @return the global object or null if the language does not support such concept + */ + protected abstract Object getLanguageGlobal(); + + /** + * Checks whether the object is provided by this language. + * + * @param object the object to check + * @return true if this language can deal with such object in native way + */ + protected abstract boolean isObjectOfLanguage(Object object); + + /** + * Represents execution environment of the {@link TruffleLanguage}. Each active + * {@link TruffleLanguage} receives instance of the environment before any code is executed upon + * it. The environment has knowledge of all active languages and can exchange symbols between + * them. + */ + public static final class Env { + private final TruffleVM vm; + private final TruffleLanguage lang; + private final Reader in; + private final Writer err; + private final Writer out; + + Env(TruffleVM vm, Constructor langConstructor, Writer out, Writer err, Reader in) { + this.vm = vm; + this.in = in; + this.err = err; + this.out = out; + try { + this.lang = (TruffleLanguage) langConstructor.newInstance(this); + } catch (Exception ex) { + throw new IllegalStateException("Cannot construct language " + langConstructor.getDeclaringClass().getName(), ex); + } + } + + /** + * Asks the environment to go through other registered languages and find whether they + * export global symbol of specified name. The expected return type is either + * TruffleObject, or one of wrappers of Java primitive types ({@link Integer}, + * {@link Double}). + * + * @param globalName the name of the symbol to search for + * @return object representing the symbol or null + */ + public Object importSymbol(String globalName) { + return API.importSymbol(vm, lang, globalName); + } + + /** + * Input associated with this {@link TruffleVM}. + * + * @return reader, never null + */ + public Reader stdIn() { + return in; + } + + /** + * Standard output writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdOut() { + return out; + } + + /** + * Standard error writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdErr() { + return err; + } + } + + private static final AccessAPI API = new AccessAPI(); + + private static final class AccessAPI extends Accessor { + @Override + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn); + return env.lang; + } + + @Override + public Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) { + return super.importSymbol(vm, queryingLang, globalName); + } + + @Override + protected Object eval(TruffleLanguage l, Source s) throws IOException { + return l.eval(s); + } + + @Override + protected Object findExportedSymbol(TruffleLanguage l, String globalName) { + return l.findExportedSymbol(globalName); + } + + @Override + protected Object languageGlobal(TruffleLanguage l) { + return l.getLanguageGlobal(); + } + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.impl; + +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.api.source.Source; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.io.Reader; +import java.io.Writer; +import java.util.ServiceLoader; + +/** + * Communication between TruffleVM and TruffleLanguage API/SPI. + */ +public abstract class Accessor { + private static Accessor API; + private static Accessor SPI; + static { + TruffleLanguage lng = new TruffleLanguage(null) { + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + }; + lng.hashCode(); + } + + protected Accessor() { + if (this.getClass().getSimpleName().endsWith("API")) { + if (API != null) { + throw new IllegalStateException(); + } + API = this; + } else { + if (SPI != null) { + throw new IllegalStateException(); + } + SPI = this; + } + } + + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); + } + + protected Object eval(TruffleLanguage l, Source s) throws IOException { + return API.eval(l, s); + } + + protected Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) { + return SPI.importSymbol(vm, queryingLang, globalName); + } + + protected Object findExportedSymbol(TruffleLanguage l, String globalName) { + return API.findExportedSymbol(l, globalName); + } + + protected Object languageGlobal(TruffleLanguage l) { + return API.languageGlobal(l); + } + + protected Object invoke(Object obj, Object[] args) throws IOException { + for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) { + return si.invoke(obj, args); + } + throw new IOException("No symbol invoker found!"); + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.impl; + +import java.io.IOException; + +/** + * XXX: Temporary class to make unit tests pass without messing with Message implementations and + * associated nodes too much. + */ +public abstract class SymbolInvoker { + protected abstract Object invoke(Object symbol, Object... args) throws IOException; +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTPrinter.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -63,4 +63,9 @@ */ String printTreeToString(Node node, int maxDepth); + /** + * Creates a textual display describing a single (non-wrapper) node, including instrumentation + * status: if Probed, and any tags. + */ + String printNodeWithInstrumentation(Node node); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.instrument; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Listener for receiving the result a client-provided {@linkplain AdvancedInstrumentRoot AST + * fragment}, when executed by a + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRoot + * @see AdvancedInstrumentRootFactory + */ +public interface AdvancedInstrumentResultListener { + + /** + * Notifies listener that a client-provided {@linkplain AdvancedInstrumentRoot AST fragment} has + * been executed by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument} with the specified result, possibly {@code null}. + *

    + * Note: Truffle will attempt to optimize implementations through partial + * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted. + * + * @param node the guest-language AST node to which the host Instrument's {@link Probe} is + * attached + * @param vFrame execution frame at the guest-language AST node + * @param result the result of this AST fragment's execution + */ + void notifyResult(Node node, VirtualFrame vFrame, Object result); + + /** + * Notifies listener that execution of client-provided {@linkplain AdvancedInstrumentRoot AST + * fragment} filed during execution by a @linkplain + * Instrument#create(AdvancedInstrumentRootFactory, String) Advanced Instrument}. + *

    + * Note: Truffle will attempt to optimize implementations through partial + * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted. + * + * @param node the guest-language AST node to which the host Instrument's {@link Probe} is + * attached + * @param vFrame execution frame at the guest-language AST node + * @param ex the exception + */ + void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex); + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.instrument; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle + * optimization, by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRootFactory + * @see AdvancedInstrumentResultListener + */ +public abstract class AdvancedInstrumentRoot extends Node implements InstrumentationNode { + + /** + * Executes this AST fragment on behalf of a client {@link Instrument}, just before the + * guest-language AST node to which the {@link Probe} holding the Instrument is executed. + * + * @param node the guest-language AST node to which the host Instrument's Probe is attached + * @param vFrame execution frame at the guest-language AST node + * @return the result of this AST fragment's execution + */ + public abstract Object executeRoot(Node node, VirtualFrame vFrame); + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.instrument; + +import com.oracle.truffle.api.nodes.*; + +/** + * Creator of {@linkplain AdvancedInstrumentRoot AST fragments} suitable for efficient execution, + * subject to full Truffle optimization, by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRoot + */ +public interface AdvancedInstrumentRootFactory { + + /** + * Provider of {@linkplain AdvancedInstrumentRoot AST fragment} instances to be executed by the + * Instrumentation Framework at a {@linkplain Probe Probed} site in a guest-language AST. + *

    + * Notes: + *

      + *
    • Once the factory has produced an AST fragment at a particular {@linkplain Node AST Node}, + * it will not be called again at that Node.
    • + *
    • In some use cases, for example to implement a breakpoint at a specific program location, + * the Probe argument will be the same for every call. Each Node argument will represent the + * same program location associated with the Probe, but in different clones of the AST.
    • + *
    • In other use cases, for example to implement a breakpoint at any Node with a particular + * {@linkplain SyntaxTag tag}, both the Probe and Node argument may differ. Implementations that + * are sensitive to the lexical context in which the AST fragment will be evaluated must take + * care to build a new, possibly different AST fragment for each request.
    • + *
    + * + * @param probe the Probe to which the Instrument requesting the AST fragment is attached + * @param node the guest-language AST location that is the context in which the requesting + * Instrument must execute the AST fragment. + * @return a newly created AST fragment suitable for execution, via instrumentation, in the + * execution context of the specified guest-language AST site. + */ + AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Thu May 28 17:44:05 2015 +0200 @@ -31,7 +31,7 @@ import com.oracle.truffle.api.source.*; // TODO (mlvdv) these statics should not be global. Move them to some kind of context. -// TODO (mlvdv) migrate factory into .impl (together with Probe)? break out nested classes? +// TODO (mlvdv) migrate factory (together with Probe)? break out nested classes? /** * A binding between: @@ -127,16 +127,22 @@ } /** - * Creates a Tool Eval Instrument: this Instrument executes efficiently, subject to + * Creates an Advanced Instrument: this Instrument executes efficiently, subject to * full Truffle optimization, a client-provided AST fragment every time the Probed node is * entered. + *

    + * Any {@link RuntimeException} thrown by execution of the fragment is caught by the framework + * and reported to the listener; there is no other notification. * - * @param toolEvalNodeFactory provider of AST fragments on behalf of the client + * @param resultListener optional client callback for results/failure notification + * @param rootFactory provider of AST fragments on behalf of the client + * @param requiredResultType optional requirement, any non-assignable result is reported to the + * the listener, if any, as a failure * @param instrumentInfo optional description of the instrument's role, intended for debugging. * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) { - return new ToolEvalInstrument(toolEvalNodeFactory, instrumentInfo); + public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class requiredResultType, String instrumentInfo) { + return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo); } // TODO (mlvdv) experimental @@ -379,22 +385,22 @@ * within a Probe's instrumentation chain, and thus directly in the executing Truffle * AST with potential for full optimization. */ - private static final class ToolEvalInstrument extends Instrument { + private static final class AdvancedInstrument extends Instrument { + + private final AdvancedInstrumentResultListener resultListener; + private final AdvancedInstrumentRootFactory rootFactory; + private final Class requiredResultType; - /** - * Client-provided supplier of new node instances to attach. - */ - private final ToolEvalNodeFactory toolEvalNodeFactory; - - private ToolEvalInstrument(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) { + private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class requiredResultType, String instrumentInfo) { super(instrumentInfo); - this.toolEvalNodeFactory = toolEvalNodeFactory; - + this.resultListener = resultListener; + this.rootFactory = rootFactory; + this.requiredResultType = requiredResultType; } @Override AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { - return new ToolEvalNodeInstrumentNode(nextNode); + return new AdvancedInstrumentNode(nextNode); } @Override @@ -406,7 +412,7 @@ return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(ToolEvalInstrument.this); + found = instrumentNode.removeFromChain(AdvancedInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -415,35 +421,62 @@ } /** - * Node that implements a {@link ToolEvalInstrument} in a particular AST. + * Node that implements a {@link AdvancedInstrument} in a particular AST. */ @NodeInfo(cost = NodeCost.NONE) - private final class ToolEvalNodeInstrumentNode extends AbstractInstrumentNode { + private final class AdvancedInstrumentNode extends AbstractInstrumentNode { - @Child ToolEvalNode toolEvalNode; + @Child private AdvancedInstrumentRoot instrumentRoot; - private ToolEvalNodeInstrumentNode(AbstractInstrumentNode nextNode) { + private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - if (toolEvalNode == null) { - final ToolEvalNode newToolEvalNodeNode = ToolEvalInstrument.this.toolEvalNodeFactory.createToolEvalNode(ToolEvalInstrument.this.probe, node); - if (newToolEvalNodeNode != null) { - toolEvalNode = newToolEvalNodeNode; - adoptChildren(); - ToolEvalInstrument.this.probe.invalidateProbeUnchanged(); + if (instrumentRoot == null) { + try { + final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node); + if (newInstrumentRoot != null) { + instrumentRoot = newInstrumentRoot; + adoptChildren(); + AdvancedInstrument.this.probe.invalidateProbeUnchanged(); + } + } catch (RuntimeException ex) { + if (resultListener != null) { + resultListener.notifyFailure(node, vFrame, ex); + } } } - if (toolEvalNode != null) { - // TODO (mlvdv) should report exception ; non-trivial architectural change - toolEvalNode.executeToolEvalNode(node, vFrame); + if (instrumentRoot != null) { + try { + final Object result = instrumentRoot.executeRoot(node, vFrame); + if (resultListener != null) { + checkResultType(result); + resultListener.notifyResult(node, vFrame, result); + } + } catch (RuntimeException ex) { + if (resultListener != null) { + resultListener.notifyFailure(node, vFrame, ex); + } + } } if (nextInstrumentNode != null) { nextInstrumentNode.enter(node, vFrame); } } + private void checkResultType(Object result) { + if (requiredResultType == null) { + return; + } + if (result == null) { + throw new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required"); + } + if (!(requiredResultType.isAssignableFrom(result.getClass()))) { + throw new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName()); + } + } + public void returnVoid(Node node, VirtualFrame vFrame) { if (nextInstrumentNode != null) { nextInstrumentNode.returnVoid(node, vFrame); @@ -464,7 +497,7 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : toolEvalNodeFactory.getClass().getSimpleName(); + return info != null ? info : rootFactory.getClass().getSimpleName(); } } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle - * optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval - * Instrument}. - * - * @see Instrument - * @see ToolEvalNodeFactory - * @see ToolEvalResultListener - */ -public abstract class ToolEvalNode extends Node implements InstrumentationNode { - - /** - * Executes this AST fragment on behalf of a client {@link Instrument}, just before the - * guest-language AST node to which the {@link Probe} holding the Instrument is executed. - * - * @param node the guest-language AST node to which the host Instrument's Probe is attached - * @param vFrame execution frame at the guest-language AST node - * @return the result of this AST fragment's execution - */ - public abstract Object executeToolEvalNode(Node node, VirtualFrame vFrame); - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.instrument; - -import com.oracle.truffle.api.nodes.*; - -/** - * Creator of {@linkplain ToolEvalNode AST fragments} suitable for efficient execution, subject to - * full Truffle optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool - * Eval Instrument}. - * - * @see Instrument - * @see ToolEvalNode - */ -public interface ToolEvalNodeFactory { - - /** - * Provider of {@linkplain ToolEvalNode AST fragment} instances for efficient execution via - * instrumentation, subject to full Truffle optimization, at a {@linkplain Probe Probed} site in - * a guest-language AST. - * - * @param probe the Probe to which the Instrument requesting the AST fragment is attached - * @param node the guest-language AST location that is the context in which the requesting - * Instrument must execute the AST fragment. - * @return a newly created AST fragment suitable for execution, via instrumentation, in the - * execution context of the specified guest-language AST site. - */ - ToolEvalNode createToolEvalNode(Probe probe, Node node); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Listener for receiving the result a client-provided {@linkplain ToolEvalNode AST fragment}, when - * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval Instrument}. - * - * @see Instrument - * @see ToolEvalNode - * @see ToolEvalNodeFactory - */ -public interface ToolEvalResultListener { - - /** - * Notifies listener that a client-provided {@linkplain ToolEvalNode AST fragment} has been - * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval - * Instrument} with the specified result, possibly {@code null}. - * - * @param node the guest-language AST node to which the host Instrument's {@link Probe} is - * attached - * @param vFrame execution frame at the guest-language AST node - * @param result the result of this AST fragment's execution - */ - void notifyToolEvalResult(Node node, VirtualFrame vFrame, Object result); - - /** - * Notifies listener that execution of client-provided {@linkplain ToolEvalNode AST fragment} - * filed during execution by a @linkplain Instrument#create(ToolEvalNodeFactory, String) Tool - * Eval Instrument}. - * - * @param node the guest-language AST node to which the host Instrument's {@link Probe} is - * attached - * @param vFrame execution frame at the guest-language AST node - * @param ex the exception - */ - void notifyToolEvalFailure(Node node, VirtualFrame vFrame, RuntimeException ex); - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTPrinter.java Thu May 28 17:44:05 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -28,6 +28,7 @@ import java.util.*; import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind; import com.oracle.truffle.api.source.*; @@ -56,6 +57,28 @@ return printTreeToString(node, maxDepth, null); } + public String printNodeWithInstrumentation(Node node) { + if (node == null) { + return "null"; + } + final StringBuilder sb = new StringBuilder(); + sb.append(nodeName(node)); + sb.append("("); + if (node instanceof InstrumentationNode) { + sb.append(instrumentInfo((InstrumentationNode) node)); + } + sb.append(sourceInfo(node)); + sb.append(NodeUtil.printSyntaxTags(node)); + sb.append(")"); + final Node parent = node.getParent(); + if (parent instanceof WrapperNode) { + final WrapperNode wrapper = (WrapperNode) parent; + sb.append(" Probed"); + sb.append(NodeUtil.printSyntaxTags(wrapper)); + } + return sb.toString(); + } + protected void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) { if (node == null) { p.print("null"); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu May 28 17:44:05 2015 +0200 @@ -561,6 +561,10 @@ printSourceAttributionTree(new PrintWriter(out), null, node, 1); } + public static void printSourceAttributionTree(PrintWriter out, Node node) { + printSourceAttributionTree(out, null, node, 1); + } + private static void printSourceAttributionTree(PrintWriter p, Node parent, Node node, int level) { if (node == null) { return; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Thu May 28 17:44:05 2015 +0200 @@ -35,32 +35,46 @@ * Representation of a guest language source code unit and its contents. Sources originate in * several ways: *

      - *
    • Literal: A named text string. These are not indexed and should be considered - * value objects; equality is defined based on contents.
      + *
    • Literal: An anonymous text string: not named and not indexed. These should + * be considered value objects; equality is defined based on contents.
      * See {@link Source#fromText(CharSequence, String)}
    • *

      + *

    • Named Literal: A text string that can be retrieved by name as if it were a + * file, but without any assumption that the name is related to a file path. Creating a new literal + * with an already existing name will replace its predecessor in the index.
      + * See {@link Source#fromNamedText(CharSequence, String)}
      + * See {@link Source#find(String)}
    • + *

      *

    • File: Each file is represented as a canonical object, indexed by the * absolute, canonical path name of the file. File contents are read lazily and contents * optionally cached.
      * See {@link Source#fromFileName(String)}
      - * See {@link Source#fromFileName(String, boolean)}
    • + * See {@link Source#fromFileName(String, boolean)}
      + * See {@link Source#find(String)} *

      *

    • URL: Each URL source is represented as a canonical object, indexed by the * URL. Contents are read eagerly and cached.
      - * See {@link Source#fromURL(URL, String)}
    • + * See {@link Source#fromURL(URL, String)}
      + * See {@link Source#find(String)} *

      - *

    • Reader: Contents are read eagerly and treated as a Literal - * .
      + *
    • Reader: Contents are read eagerly and treated as an anonymous + * (non-indexed) Literal .
      * See {@link Source#fromReader(Reader, String)}
    • *

      - *

    • Pseudo File: A literal text string that can be retrieved by name as if it - * were a file, unlike literal sources; useful for testing.
      - * See {@link Source#asPseudoFile(CharSequence, String)}
    • + *
    • Sub-Source: A representation of the contents of a sub-range of another + * {@link Source}.
      + * See @link {@link Source#subSource(Source, int, int)}
      + * See @link {@link Source#subSource(Source, int)}
    • + *

      + *

    • AppendableSource: Literal contents are provided by the client, + * incrementally, after the instance is created.
      + * See {@link Source#fromAppendableText(String)}
      + * See {@link Source#fromNamedAppendableText(String)}
    • *
    *

    * File cache: *

      - *
    1. File content caching is optional, off by default.
    2. + *
    3. File content caching is optional, on by default.
    4. *
    5. The first access to source file contents will result in the contents being read, and (if * enabled) cached.
    6. *
    7. If file contents have been cached, access to contents via {@link Source#getInputStream()} or @@ -128,14 +142,24 @@ */ private static final List> allSources = Collections.synchronizedList(new ArrayList>()); - // Files and pseudo files are indexed. - private static final Map> filePathToSource = new HashMap<>(); + /** + * Index of all named sources. + */ + private static final Map> nameToSource = new HashMap<>(); private static boolean fileCacheEnabled = true; private static final List sourceListeners = new ArrayList<>(); /** + * Locates an existing instance by the name under which it was indexed. + */ + public static Source find(String name) { + final WeakReference nameRef = nameToSource.get(name); + return nameRef == null ? null : nameRef.get(); + } + + /** * Gets the canonical representation of a source file, whose contents will be read lazily and * then cached. * @@ -146,7 +170,7 @@ */ public static Source fromFileName(String fileName, boolean reset) throws IOException { - final WeakReference nameRef = filePathToSource.get(fileName); + final WeakReference nameRef = nameToSource.get(fileName); Source source = nameRef == null ? null : nameRef.get(); if (source == null) { final File file = new File(fileName); @@ -154,11 +178,11 @@ throw new IOException("Can't read file " + fileName); } final String path = file.getCanonicalPath(); - final WeakReference pathRef = filePathToSource.get(path); + final WeakReference pathRef = nameToSource.get(path); source = pathRef == null ? null : pathRef.get(); if (source == null) { source = new FileSource(file, fileName, path); - filePathToSource.put(path, new WeakReference<>(source)); + nameToSource.put(path, new WeakReference<>(source)); } } if (reset) { @@ -193,17 +217,17 @@ */ public static Source fromFileName(CharSequence chars, String fileName) throws IOException { - final WeakReference nameRef = filePathToSource.get(fileName); + final WeakReference nameRef = nameToSource.get(fileName); Source source = nameRef == null ? null : nameRef.get(); if (source == null) { final File file = new File(fileName); // We are going to trust that the fileName is readable. final String path = file.getCanonicalPath(); - final WeakReference pathRef = filePathToSource.get(path); + final WeakReference pathRef = nameToSource.get(path); source = pathRef == null ? null : pathRef.get(); if (source == null) { source = new FileSource(file, fileName, path, chars); - filePathToSource.put(path, new WeakReference<>(source)); + nameToSource.put(path, new WeakReference<>(source)); } } notifyNewSource(source).tagAs(Tags.FROM_FILE); @@ -211,8 +235,7 @@ } /** - * Creates a non-canonical source from literal text. If an already created literal source must - * be retrievable by name, use {@link #asPseudoFile(CharSequence, String)}. + * Creates an anonymous source from literal text: not named and not indexed. * * @param chars textual source code * @param description a note about the origin, for error messages and debugging @@ -226,6 +249,79 @@ } /** + * Creates an anonymous source from literal text that is provided incrementally after creation: + * not named and not indexed. + * + * @param description a note about the origin, for error messages and debugging + * @return a newly created, non-indexed, initially empty, appendable source representation + */ + public static Source fromAppendableText(String description) { + final Source source = new AppendableLiteralSource(description); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); + return source; + } + + /** + * Creates a source from literal text that can be retrieved by name, with no assumptions about + * the structure or meaning of the name. If the name is already in the index, the new instance + * will replace the previously existing instance in the index. + * + * @param chars textual source code + * @param name string to use for indexing/lookup + * @return a newly created, source representation + */ + public static Source fromNamedText(CharSequence chars, String name) { + final Source source = new LiteralSource(name, chars.toString()); + nameToSource.put(name, new WeakReference<>(source)); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); + return source; + } + + /** + * Creates a source from literal text that is provided incrementally after creation and which + * can be retrieved by name, with no assumptions about the structure or meaning of the name. If + * the name is already in the index, the new instance will replace the previously existing + * instance in the index. + * + * @param name string to use for indexing/lookup + * @return a newly created, indexed, initially empty, appendable source representation + */ + public static Source fromNamedAppendableText(String name) { + final Source source = new AppendableLiteralSource(name); + nameToSource.put(name, new WeakReference<>(source)); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); + return source; + } + + /** + * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range of + * an existing {@link Source}. + * + * @param base an existing Source instance + * @param baseCharIndex 0-based index of the first character of the sub-range + * @param length the number of characters in the sub-range + * @return a new instance representing a sub-range of another Source + * @throws IllegalArgumentException if the specified sub-range is not contained in the base + */ + public static Source subSource(Source base, int baseCharIndex, int length) { + final SubSource subSource = SubSource.create(base, baseCharIndex, length); + return subSource; + } + + /** + * Creates a {@linkplain Source Source instance} that represents the contents of a sub-range at + * the end of an existing {@link Source}. + * + * @param base an existing Source instance + * @param baseCharIndex 0-based index of the first character of the sub-range + * @return a new instance representing a sub-range at the end of another Source + * @throws IllegalArgumentException if the index is out of range + */ + public static Source subSource(Source base, int baseCharIndex) { + return subSource(base, baseCharIndex, base.getLength() - baseCharIndex); + } + + /** * Creates a source whose contents will be read immediately from a URL and cached. * * @param url @@ -286,21 +382,6 @@ return source; } - /** - * Creates a source from literal text, but which acts as a file and can be retrieved by name - * (unlike other literal sources); intended for testing. - * - * @param chars textual source code - * @param pseudoFileName string to use for indexing/lookup - * @return a newly created, source representation, canonical with respect to its name - */ - public static Source asPseudoFile(CharSequence chars, String pseudoFileName) { - final Source source = new LiteralSource(pseudoFileName, chars.toString()); - filePathToSource.put(pseudoFileName, new WeakReference<>(source)); - notifyNewSource(source).tagAs(Tags.FROM_LITERAL); - return source; - } - // TODO (mlvdv) enable per-file choice whether to cache? /** * Enables/disables caching of file contents, disabled by default. Caching of sources @@ -372,7 +453,7 @@ private final ArrayList tags = new ArrayList<>(); - Source() { + private Source() { } private TextMap textMap = null; @@ -448,7 +529,7 @@ * Gets the number of characters in the source. */ public final int getLength() { - return checkTextMap().length(); + return getTextMap().length(); } /** @@ -467,9 +548,8 @@ * Gets the text (not including a possible terminating newline) in a (1-based) numbered line. */ public final String getCode(int lineNumber) { - checkTextMap(); - final int offset = textMap.lineStartOffset(lineNumber); - final int length = textMap.lineLength(lineNumber); + final int offset = getTextMap().lineStartOffset(lineNumber); + final int length = getTextMap().lineLength(lineNumber); return getCode().substring(offset, offset + length); } @@ -478,7 +558,7 @@ * source without a terminating newline count as a line. */ public final int getLineCount() { - return checkTextMap().lineCount(); + return getTextMap().lineCount(); } /** @@ -488,7 +568,7 @@ * @throws IllegalArgumentException if the offset is outside the text contents */ public final int getLineNumber(int offset) throws IllegalArgumentException { - return checkTextMap().offsetToLine(offset); + return getTextMap().offsetToLine(offset); } /** @@ -497,7 +577,7 @@ * @throws IllegalArgumentException if the offset is outside the text contents */ public final int getColumnNumber(int offset) throws IllegalArgumentException { - return checkTextMap().offsetToCol(offset); + return getTextMap().offsetToCol(offset); } /** @@ -506,7 +586,7 @@ * @throws IllegalArgumentException if there is no such line in the text */ public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException { - return checkTextMap().lineStartOffset(lineNumber); + return getTextMap().lineStartOffset(lineNumber); } /** @@ -516,7 +596,17 @@ * @throws IllegalArgumentException if there is no such line in the text */ public final int getLineLength(int lineNumber) throws IllegalArgumentException { - return checkTextMap().lineLength(lineNumber); + return getTextMap().lineLength(lineNumber); + } + + /** + * Append text to a Source explicitly created as Appendable. + * + * @param chars the text to append + * @throws UnsupportedOperationException by concrete subclasses that do not support appending + */ + public void appendCode(CharSequence chars) { + throw new UnsupportedOperationException(); } /** @@ -556,9 +646,8 @@ * @throws IllegalStateException if the source is one of the "null" instances */ public final SourceSection createSection(String identifier, int startLine, int startColumn, int length) { - checkTextMap(); - final int lineStartOffset = textMap.lineStartOffset(startLine); - if (startColumn > textMap.lineLength(startLine)) { + final int lineStartOffset = getTextMap().lineStartOffset(startLine); + if (startColumn > getTextMap().lineLength(startLine)) { throw new IllegalArgumentException("column out of range"); } final int startOffset = lineStartOffset + startColumn - 1; @@ -586,10 +675,8 @@ */ public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException { checkRange(charIndex, length); - checkTextMap(); final int startLine = getLineNumber(charIndex); final int startColumn = charIndex - getLineStartOffset(startLine) + 1; - return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length); } @@ -610,9 +697,8 @@ * @throws IllegalStateException if the source is one of the "null" instances */ public final SourceSection createSection(String identifier, int lineNumber) { - checkTextMap(); - final int charIndex = textMap.lineStartOffset(lineNumber); - final int length = textMap.lineLength(lineNumber); + final int charIndex = getTextMap().lineStartOffset(lineNumber); + final int length = getTextMap().lineLength(lineNumber); return createSection(identifier, charIndex, length); } @@ -627,13 +713,25 @@ return new LineLocationImpl(this, lineNumber); } - private TextMap checkTextMap() { + /** + * An object suitable for using as a key into a hashtable that defines equivalence between + * different source types. + */ + protected Object getHashKey() { + return getName(); + } + + protected final TextMap getTextMap() { if (textMap == null) { textMap = createTextMap(); } return textMap; } + protected final void clearTextMap() { + textMap = null; + } + protected TextMap createTextMap() { final String code = getCode(); if (code == null) { @@ -644,22 +742,22 @@ private static final class LiteralSource extends Source { - private final String name; // Name used originally to describe the source + private final String description; private final String code; - public LiteralSource(String name, String code) { - this.name = name; + public LiteralSource(String description, String code) { + this.description = description; this.code = code; } @Override public String getName() { - return name; + return description; } @Override public String getShortName() { - return name; + return description; } @Override @@ -669,7 +767,7 @@ @Override public String getPath() { - return name; + return description; } @Override @@ -688,11 +786,7 @@ @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + name.hashCode(); - result = prime * result + (code == null ? 0 : code.hashCode()); - return result; + return description.hashCode(); } @Override @@ -703,11 +797,69 @@ if (obj == null) { return false; } - if (!(obj instanceof LiteralSource)) { - return false; + if (obj instanceof LiteralSource) { + LiteralSource other = (LiteralSource) obj; + return description.equals(other.description); } - LiteralSource other = (LiteralSource) obj; - return name.equals(other.name) && code.equals(other.code); + return false; + } + } + + private static final class AppendableLiteralSource extends Source { + private String description; + final List codeList = new ArrayList<>(); + + public AppendableLiteralSource(String description) { + this.description = description; + } + + @Override + public String getName() { + return description; + } + + @Override + public String getShortName() { + return description; + } + + @Override + public String getCode() { + return getCodeFromIndex(0); + } + + @Override + public String getPath() { + return description; + } + + @Override + public URL getURL() { + return null; + } + + @Override + public Reader getReader() { + return new StringReader(getCode()); + } + + @Override + protected void reset() { + } + + private String getCodeFromIndex(int index) { + StringBuilder sb = new StringBuilder(); + for (int i = index; i < codeList.size(); i++) { + CharSequence s = codeList.get(i); + sb.append(s); + } + return sb.toString(); + } + + @Override + public void appendCode(CharSequence chars) { + codeList.add(chars); + clearTextMap(); } } @@ -745,6 +897,11 @@ } @Override + protected Object getHashKey() { + return path; + } + + @Override public String getCode() { if (fileCacheEnabled) { if (code == null || timeStamp != file.lastModified()) { @@ -807,7 +964,6 @@ protected void reset() { this.code = null; } - } private static final class URLSource extends Source { @@ -867,7 +1023,61 @@ @Override protected void reset() { } + } + private static final class SubSource extends Source { + private final Source base; + private final int baseIndex; + private final int subLength; + + private static SubSource create(Source base, int baseIndex, int length) { + if (baseIndex < 0 || length < 0 || baseIndex + length > base.getLength()) { + throw new IllegalArgumentException("text positions out of range"); + } + return new SubSource(base, baseIndex, length); + } + + private SubSource(Source base, int baseIndex, int length) { + this.base = base; + this.baseIndex = baseIndex; + this.subLength = length; + } + + @Override + protected void reset() { + assert false; + } + + @Override + public String getName() { + return base.getName(); + } + + @Override + public String getShortName() { + return base.getShortName(); + } + + @Override + public String getPath() { + return base.getPath(); + } + + @Override + public URL getURL() { + return null; + } + + @Override + public Reader getReader() { + assert false; + return null; + } + + @Override + public String getCode() { + return base.getCode(baseIndex, subLength); + } } private static final class BytesSource extends Source { @@ -1132,7 +1342,7 @@ final int prime = 31; int result = 1; result = prime * result + line; - result = prime * result + source.hashCode(); + result = prime * result + source.getHashKey().hashCode(); return result; } @@ -1151,7 +1361,7 @@ if (line != other.line) { return false; } - return source.equals(other.source); + return source.getHashKey().equals(other.source.getHashKey()); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java Thu May 28 17:44:05 2015 +0200 @@ -52,6 +52,8 @@ * @see #createBinaryProfile() */ public abstract class ConditionProfile extends NodeCloneable { + ConditionProfile() { + } public abstract boolean profile(boolean value); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.vm; + +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.TruffleLanguage.Registration; +import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.source.Source; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.io.Writer; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Virtual machine for Truffle based languages. Use {@link #newVM()} to create new isolated virtual + * machine ready for execution of various languages. All the languages in a single virtual machine + * see each other exported global symbols and can co-operate. Use {@link #newVM()} multiple times to + * create different, isolated virtual machines completely separated from each other. + *

      + * Once instantiated use {@link #eval(java.net.URI)} with a reference to a file or URL or directly + * pass code snippet into the virtual machine via {@link #eval(java.lang.String, java.lang.String)}. + * Support for individual languages is initialized on demand - e.g. once a file of certain mime type + * is about to be processed, its appropriate engine (if found), is initialized. Once an engine gets + * initialized, it remains so, until the virtual machine isn't garbage collected. + *

      + * The TruffleVM is single-threaded and tries to enforce that. It records the thread it + * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from + * the same thread. + */ +public final class TruffleVM { + private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName()); + private static final SPIAccessor SPI = new SPIAccessor(); + private final Thread initThread; + private final Map langs; + private final Reader in; + private final Writer err; + private final Writer out; + + /** + * Private & temporary only constructor. + */ + private TruffleVM() { + this.initThread = null; + this.in = null; + this.err = null; + this.out = null; + this.langs = null; + } + + /** + * Real constructor used from the builder. + * + * @param out stdout + * @param err stderr + * @param in stdin + */ + private TruffleVM(Writer out, Writer err, Reader in) { + this.out = out; + this.err = err; + this.in = in; + this.initThread = Thread.currentThread(); + this.langs = new HashMap<>(); + Enumeration en; + try { + en = loader().getResources("META-INF/truffle/language"); + } catch (IOException ex) { + throw new IllegalStateException("Cannot read list of Truffle languages", ex); + } + while (en.hasMoreElements()) { + URL u = en.nextElement(); + Properties p; + try { + p = new Properties(); + try (InputStream is = u.openStream()) { + p.load(is); + } + } catch (IOException ex) { + LOG.log(Level.CONFIG, "Cannot process " + u + " as language definition", ex); + continue; + } + Language l = new Language(p); + for (String mimeType : l.getMimeTypes()) { + langs.put(mimeType, l); + } + } + } + + static ClassLoader loader() { + ClassLoader l = TruffleVM.class.getClassLoader(); + if (l == null) { + l = ClassLoader.getSystemClassLoader(); + } + return l; + } + + /** + * Creation of new Truffle virtual machine. Use the {@link Builder} methods to configure your + * virtual machine and then create one using {@link Builder#build()}: + * + *

      +     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
      +     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
      +     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
      +     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
      +     *     .{@link Builder#build() build()};
      +     * 
      + * + * It searches for {@link Registration languages registered} in the system class loader and + * makes them available for later evaluation via + * {@link #eval(java.lang.String, java.lang.String)} methods. + * + * @return new, isolated virtual machine with pre-registered languages + */ + public static TruffleVM.Builder newVM() { + // making Builder non-static inner class is a + // nasty trick to avoid the Builder class to appear + // in Javadoc next to TruffleVM class + TruffleVM vm = new TruffleVM(); + return vm.new Builder(); + } + + /** + * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the + * end create new {@link TruffleVM virtual machine}: + * + *
      +     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
      +     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
      +     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
      +     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
      +     *     .{@link Builder#build() build()};
      +     * 
      + */ + public final class Builder { + private Writer out; + private Writer err; + private Reader in; + + Builder() { + } + + /** + * Changes the defaut output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdOut(Writer w) { + out = w; + return this; + } + + /** + * Changes the error output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#err}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdErr(Writer w) { + err = w; + return this; + } + + /** + * Changes the defaut input for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param r the reader to use as input + * @return instance of this builder + */ + public Builder stdIn(Reader r) { + in = r; + return this; + } + + /** + * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from + * values passed into configuration methods in this class. + * + * @return new, isolated virtual machine with pre-registered languages + */ + public TruffleVM build() { + if (out == null) { + out = new OutputStreamWriter(System.out); + } + if (err == null) { + err = new OutputStreamWriter(System.err); + } + if (in == null) { + in = new InputStreamReader(System.in); + } + return new TruffleVM(out, err, in); + } + } + + /** + * Descriptions of languages supported in this Truffle virtual machine. + * + * @return an immutable map with keys being mimetypes and values the {@link Language + * descriptions} of associated languages + */ + public Map getLanguages() { + return Collections.unmodifiableMap(langs); + } + + /** + * Evaluates file located on a given URL. Is equivalent to loading the content of a file and + * executing it via {@link #eval(java.lang.String, java.lang.String)} with a mime type guess + * based on the file's extension and/or content. + * + * @param location the location of a file to execute + * @return result of a processing the file, possibly null + * @throws IOException exception to signal I/O problems or problems with processing the file's + * content + */ + public Object eval(URI location) throws IOException { + checkThread(); + Source s; + String mimeType; + if (location.getScheme().equals("file")) { + File file = new File(location); + s = Source.fromFileName(file.getPath(), true); + if (file.getName().endsWith(".c")) { + mimeType = "text/x-c"; + } else if (file.getName().endsWith(".sl")) { + mimeType = "application/x-sl"; + } else { + mimeType = Files.probeContentType(file.toPath()); + } + } else { + URL url = location.toURL(); + s = Source.fromURL(url, location.toString()); + URLConnection conn = url.openConnection(); + mimeType = conn.getContentType(); + } + TruffleLanguage l = getTruffleLang(mimeType); + if (l == null) { + throw new IOException("No language for " + location + " with mime type " + mimeType + " found. Supported types: " + langs.keySet()); + } + return SPI.eval(l, s); + } + + /** + * Evaluates code snippet. Chooses a language registered for a given mime type (throws + * {@link IOException} if there is none). And passes the specified code to it for execution. + * + * @param mimeType mime type of the code snippet - chooses the right language + * @param reader the source of code snippet to execute + * @return result of an exceution, possibly null + * @throws IOException thrown to signal errors while processing the code + */ + public Object eval(String mimeType, Reader reader) throws IOException { + checkThread(); + TruffleLanguage l = getTruffleLang(mimeType); + if (l == null) { + throw new IOException("No language for mime type " + mimeType + " found. Supported types: " + langs.keySet()); + } + return SPI.eval(l, Source.fromReader(reader, mimeType)); + } + + /** + * Evaluates code snippet. Chooses a language registered for a given mime type (throws + * {@link IOException} if there is none). And passes the specified code to it for execution. + * + * @param mimeType mime type of the code snippet - chooses the right language + * @param code the code snippet to execute + * @return result of an exceution, possibly null + * @throws IOException thrown to signal errors while processing the code + */ + public Object eval(String mimeType, String code) throws IOException { + checkThread(); + TruffleLanguage l = getTruffleLang(mimeType); + if (l == null) { + throw new IOException("No language for mime type " + mimeType + " found. Supported types: " + langs.keySet()); + } + return SPI.eval(l, Source.fromText(code, mimeType)); + } + + /** + * Looks global symbol provided by one of initialized languages up. First of all execute your + * program via one of your {@link #eval(java.lang.String, java.lang.String)} and then look + * expected symbol up using this method. + *

      + * The names of the symbols are language dependant, but for example the Java language bindings + * follow the specification for method references: + *

        + *
      • "java.lang.Exception::new" is a reference to constructor of {@link Exception} + *
      • "java.lang.Integer::valueOf" is a reference to static method in {@link Integer} class + *
      + * Once an symbol is obtained, it remembers values for fast acces and is ready for being + * invoked. + * + * @param globalName the name of the symbol to find + * @return found symbol or null if it has not been found + */ + public Symbol findGlobalSymbol(String globalName) { + checkThread(); + Object obj = null; + Object global = null; + for (Language dl : langs.values()) { + TruffleLanguage l = dl.getImpl(); + obj = SPI.findExportedSymbol(l, globalName); + if (obj != null) { + global = SPI.languageGlobal(l); + break; + } + } + return obj == null ? null : new Symbol(obj, global); + } + + private void checkThread() { + if (initThread != Thread.currentThread()) { + throw new IllegalStateException("TruffleVM created on " + initThread.getName() + " but used on " + Thread.currentThread().getName()); + } + } + + private TruffleLanguage getTruffleLang(String mimeType) { + checkThread(); + Language l = langs.get(mimeType); + return l == null ? null : l.getImpl(); + } + + /** + * Represents {@link TruffleVM#findGlobalSymbol(java.lang.String) global symbol} provided by one + * of the initialized languages in {@link TruffleVM Truffle virtual machine}. + */ + public class Symbol { + private final Object obj; + private final Object global; + + Symbol(Object obj, Object global) { + this.obj = obj; + this.global = global; + } + + /** + * Invokes the symbol. If the symbol represents a function, then it should be invoked with + * provided arguments. If the symbol represents a field, then first argument (if provided) + * should set the value to the field; the return value should be the actual value of the + * field when the invoke method returns. + * + * @param thiz this/self in language that support such concept; use null to let + * the language use default this/self or ignore the value + * @param args arguments to pass when invoking the symbol + * @return the value returned by invoking the symbol + * @throws IOException signals problem during execution + */ + public Object invoke(Object thiz, Object... args) throws IOException { + List arr = new ArrayList<>(); + if (thiz == null) { + if (global != null) { + arr.add(global); + } + } else { + arr.add(thiz); + } + arr.addAll(Arrays.asList(args)); + return SPI.invoke(obj, arr.toArray()); + } + } + + /** + * Description of a language registered in {@link TruffleVM Truffle virtual machine}. Languages + * are registered by {@link Registration} annotation which stores necessary information into a + * descriptor inside of the language's JAR file. When a new {@link TruffleVM} is created, it + * reads all available descritors and creates {@link Language} objects to represent them. One + * can obtain a {@link #getName() name} or list of supported {@link #getMimeTypes() mimetypes} + * for each language. The actual language implementation is not initialized until + * {@link TruffleVM#eval(java.lang.String, java.lang.String) a code is evaluated} in it. + */ + public final class Language { + private final Properties props; + private TruffleLanguage impl; + + Language(Properties props) { + this.props = props; + } + + /** + * Mimetypes recognized by the language. + * + * @return returns immutable set of recognized mimetypes + */ + public Set getMimeTypes() { + TreeSet ts = new TreeSet<>(); + for (int i = 0;; i++) { + String mt = props.getProperty("mimeType." + i); + if (mt == null) { + break; + } + ts.add(mt); + } + return Collections.unmodifiableSet(ts); + } + + /** + * Human readable name of the language. Think of C, Ruby, JS, etc. + * + * @return string giving the language a name + */ + public String getName() { + return props.getProperty("name"); + } + + TruffleLanguage getImpl() { + if (impl == null) { + String n = props.getProperty("className"); + try { + Class langClazz = Class.forName(n, true, loader()); + Constructor constructor = langClazz.getConstructor(Env.class); + impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in); + } catch (Exception ex) { + throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + n, ex); + } + } + return impl; + } + + @Override + public String toString() { + return "[" + getName() + " for " + getMimeTypes() + "]"; + } + } // end of Language + + private static class SPIAccessor extends Accessor { + @Override + public Object importSymbol(TruffleVM vm, TruffleLanguage ownLang, String globalName) { + Set uniqueLang = new LinkedHashSet<>(vm.langs.values()); + for (Language dl : uniqueLang) { + TruffleLanguage l = dl.getImpl(); + if (l == ownLang) { + continue; + } + Object obj = SPI.findExportedSymbol(l, globalName); + if (obj != null) { + return obj; + } + } + return null; + } + + @Override + public TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); + } + + @Override + public Object eval(TruffleLanguage l, Source s) throws IOException { + return super.eval(l, s); + } + + @Override + public Object findExportedSymbol(TruffleLanguage l, String globalName) { + return super.findExportedSymbol(l, globalName); + } + + @Override + public Object languageGlobal(TruffleLanguage l) { + return super.languageGlobal(l); + } + + @Override + public Object invoke(Object obj, Object[] args) throws IOException { + return super.invoke(obj, args); + } + } // end of SPIAccessor +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,12 @@ + + + + Truffle Virtual Machine + + + + +
      Central place to control Truffle Virtual Machine and + all languages hosted in it.
      + + diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/META-INF/services/javax.annotation.processing.Processor --- a/graal/com.oracle.truffle.dsl.processor/src/META-INF/services/javax.annotation.processing.Processor Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/META-INF/services/javax.annotation.processing.Processor Thu May 28 17:44:05 2015 +0200 @@ -1,2 +1,3 @@ com.oracle.truffle.dsl.processor.TruffleProcessor com.oracle.truffle.dsl.processor.verify.VerifyTruffleProcessor +com.oracle.truffle.dsl.processor.LanguageRegistrationProcessor diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, 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.dsl.processor; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; + +public class ExpectError { + + public static void assertNoErrorExpected(ProcessingEnvironment processingEnv, Element element) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME); + if (eee != null) { + for (AnnotationMirror am : element.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", element); + } + } + } + } + + public static boolean isExpectedError(ProcessingEnvironment processingEnv, Element element, String message) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME); + if (eee != null) { + for (AnnotationMirror am : element.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + Map vals = am.getElementValues(); + if (vals.size() == 1) { + AnnotationValue av = vals.values().iterator().next(); + if (av.getValue() instanceof List) { + List arr = (List) av.getValue(); + for (Object o : arr) { + if (o instanceof AnnotationValue) { + AnnotationValue ov = (AnnotationValue) o; + if (message.equals(ov.getValue())) { + return true; + } + } + } + } + } + } + } + } + return false; + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, 2015, 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.dsl.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; +import javax.tools.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.TruffleLanguage.Registration; + +@SupportedAnnotationTypes("com.oracle.truffle.api.*") +public final class LanguageRegistrationProcessor extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private void createProviderFile(TypeElement language, Registration annotation) { + String filename = "META-INF/truffle/language"; + try { + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, language); + Properties p = new Properties(); + String className = processingEnv.getElementUtils().getBinaryName(language).toString(); + p.setProperty("name", annotation.name()); + p.setProperty("className", className); + String[] mimes = annotation.mimeType(); + for (int i = 0; i < mimes.length; i++) { + p.setProperty("mimeType." + i, mimes[i]); + } + try (OutputStream os = file.openOutputStream()) { + p.store(os, "Generated by " + LanguageRegistrationProcessor.class.getName()); + } + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), language); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (Element e : roundEnv.getElementsAnnotatedWith(Registration.class)) { + Registration annotation = e.getAnnotation(Registration.class); + if (annotation != null && e.getKind() == ElementKind.CLASS) { + if (!e.getModifiers().contains(Modifier.PUBLIC)) { + emitError("Registered language class must be public", e); + continue; + } + if (e.getEnclosingElement().getKind() != ElementKind.PACKAGE && !e.getModifiers().contains(Modifier.STATIC)) { + emitError("Registered language inner-class must be static", e); + continue; + } + TypeMirror truffleLang = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType(); + if (!processingEnv.getTypeUtils().isAssignable(e.asType(), truffleLang)) { + emitError("Registered language class must subclass TruffleLanguage", e); + continue; + } + boolean found = false; + for (Element mem : e.getEnclosedElements()) { + if (mem.getKind() != ElementKind.CONSTRUCTOR) { + continue; + } + ExecutableElement ee = (ExecutableElement) mem; + if (ee.getParameters().size() != 1) { + continue; + } + if (!ee.getModifiers().contains(Modifier.PUBLIC)) { + continue; + } + TypeMirror env = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.Env.class.getCanonicalName()).asType(); + if (processingEnv.getTypeUtils().isSameType(ee.getParameters().get(0).asType(), env)) { + found = true; + break; + } + } + if (!found) { + emitError("Language must have a public constructor accepting TruffleLanguage.Env as parameter", e); + continue; + } + assertNoErrorExpected(e); + createProviderFile((TypeElement) e, annotation); + } + } + + return true; + } + + void assertNoErrorExpected(Element e) { + ExpectError.assertNoErrorExpected(processingEnv, e); + } + + void emitError(String msg, Element e) { + if (ExpectError.isExpectedError(processingEnv, e, msg)) { + return; + } + processingEnv.getMessager().printMessage(Kind.ERROR, msg, e); + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Thu May 28 17:44:05 2015 +0200 @@ -44,6 +44,8 @@ */ public final class TruffleTypes { + public static final String EXPECT_ERROR_CLASS_NAME = "com.oracle.truffle.api.dsl.test.ExpectError"; + private final DeclaredType node; private final ArrayType nodeArray; private final TypeMirror unexpectedValueException; @@ -94,7 +96,7 @@ nodeFactory = getRequired(context, NodeFactory.class); nodeFactoryBase = getRequired(context, NodeFactoryBase.class); dslMetadata = getRequired(context, DSLMetadata.class); - expectError = (TypeElement) getRequired(context, ExpectError.class).asElement(); + expectError = getOptional(context, EXPECT_ERROR_CLASS_NAME); generateNodeFactory = getRequired(context, GenerateNodeFactory.class); } @@ -158,6 +160,10 @@ return (DeclaredType) type; } + private static TypeElement getOptional(ProcessorContext context, String name) { + return context.getEnvironment().getElementUtils().getTypeElement(name); + } + public TypeMirror getInvalidAssumption() { return invalidAssumption; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Thu May 28 17:44:05 2015 +0200 @@ -168,7 +168,12 @@ CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + + if (factoryList.size() > 1) { + builder.startStaticCall(context.getType(Arrays.class), "asList"); + } else { + builder.startStaticCall(context.getType(Collections.class), "singletonList"); + } for (NodeData child : factoryList) { builder.startGroup(); diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Thu May 28 17:44:05 2015 +0200 @@ -37,7 +37,7 @@ @DSLOptions public class TypeSystemParser extends AbstractParser { - public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); + public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class); @Override public Class getAnnotationType() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java Thu May 28 17:44:05 2015 +0200 @@ -34,9 +34,10 @@ import javax.tools.Diagnostic.Kind; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.dsl.processor.*; -@SupportedSourceVersion(SourceVersion.RELEASE_7) -@SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary"}) +@SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary", "com.oracle.truffle.api.nodes.Node.Child"}) public class VerifyTruffleProcessor extends AbstractProcessor { @Override public SourceVersion getSupportedSourceVersion() { @@ -113,9 +114,28 @@ scope = null; } } + + for (Element e : roundEnv.getElementsAnnotatedWith(Child.class)) { + if (e.getModifiers().contains(Modifier.FINAL)) { + emitError("@Child field cannot be final", e); + continue; + } + assertNoErrorExpected(e); + } return false; } + void assertNoErrorExpected(Element element) { + ExpectError.assertNoErrorExpected(processingEnv, element); + } + + void emitError(String message, Element element) { + if (ExpectError.isExpectedError(processingEnv, element, message)) { + return; + } + processingEnv.getMessager().printMessage(Kind.ERROR, message, element); + } + /** * Determines if a given exception is (most likely) caused by Bug 367599. diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.interop/src/META-INF/services/com.oracle.truffle.api.impl.SymbolInvoker --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.interop/src/META-INF/services/com.oracle.truffle.api.impl.SymbolInvoker Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,1 @@ +com.oracle.truffle.interop.SymbolInvokerImpl diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.interop; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.impl.SymbolInvoker; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.interop.messages.Execute; +import com.oracle.truffle.interop.messages.Receiver; +import com.oracle.truffle.interop.node.ForeignObjectAccessNode; +import java.io.IOException; + +public final class SymbolInvokerImpl extends SymbolInvoker { + static final FrameDescriptor UNUSED_FRAMEDESCRIPTOR = new FrameDescriptor(); + + @Override + protected Object invoke(Object symbol, Object... arr) throws IOException { + ForeignObjectAccessNode executeMain = ForeignObjectAccessNode.getAccess(Execute.create(Receiver.create(), arr.length)); + CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(executeMain, (TruffleObject) symbol, arr)); + VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR); + return callTarget.call(frame); + } + + private static class TemporaryRoot extends RootNode { + @Child private ForeignObjectAccessNode foreignAccess; + private final TruffleObject function; + private final Object[] args; + + public TemporaryRoot(ForeignObjectAccessNode foreignAccess, TruffleObject function, Object... args) { + this.foreignAccess = foreignAccess; + this.function = function; + this.args = args; + } + + @Override + public Object execute(VirtualFrame frame) { + return foreignAccess.executeForeign(frame, function, args); + } + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleGlobalScope.java --- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleGlobalScope.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.interop; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.interop.*; - -public interface TruffleGlobalScope { - void exportTruffleObject(Object identifier, TruffleObject object); - - FrameSlot getFrameSlot(Object identifier); - - TruffleObject getTruffleObject(FrameSlot slot); - - boolean contains(Object identifier); -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleLanguage.java --- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/TruffleLanguage.java Thu May 28 16:54:14 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2014, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.interop; - -import com.oracle.truffle.api.interop.*; - -public interface TruffleLanguage { - String getLanguageName(); - - Object run(String[] arguments); - - void setTruffleGlobalScope(TruffleGlobalScope globalScope); - - TruffleObject getLanguageGlobal(); - - boolean isObjectOfLanguage(TruffleObject object); - -} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 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.sl.test; + +import com.oracle.truffle.api.test.vm.TruffleTCK; +import com.oracle.truffle.api.vm.TruffleVM; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * This is the way to verify your language implementation is compatible. + * + */ +public class SLTckTest extends TruffleTCK { + @Test + public void testVerifyPresence() { + TruffleVM vm = TruffleVM.newVM().build(); + assertTrue("Our language is present", vm.getLanguages().containsKey("application/x-sl")); + } + + @Override + protected TruffleVM prepareVM() throws Exception { + TruffleVM vm = TruffleVM.newVM().build(); + vm.eval("application/x-sl", // your langage + "function fourtyTwo() {\n" + // your script + " return 42;\n" + // + "}\n" + // + "function plus(a, b) {\n" + // + " return a + b;\n" + // + "}\n" // + ); + return vm; + } + + @Override + protected String fourtyTwo() { + return "fourtyTwo"; + } + + @Override + protected String plusInt() { + return "plus"; + } +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Thu May 28 17:44:05 2015 +0200 @@ -37,11 +37,9 @@ import org.junit.runners.model.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.sl.*; +import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.sl.SLMain; import com.oracle.truffle.sl.builtins.*; -import com.oracle.truffle.sl.factory.*; -import com.oracle.truffle.sl.runtime.*; import com.oracle.truffle.sl.test.SLTestRunner.TestCase; public final class SLTestRunner extends ParentRunner { @@ -165,19 +163,18 @@ notifier.fireTestStarted(testCase.name); ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream printer = new PrintStream(out); + PrintWriter printer = new PrintWriter(out); try { - SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer); - for (NodeFactory builtin : builtins) { - context.installBuiltin(builtin); - } - final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); - SLMain.run(context, source, null, repeats); + TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build(); + + String script = readAllLines(testCase.path); + SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins); + printer.flush(); String actualOutput = new String(out.toByteArray()); - Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput); + Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput); } catch (Throwable ex) { - notifier.fireTestFailure(new Failure(testCase.name, ex)); + notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex))); } finally { notifier.fireTestFinished(testCase.name); } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Thu May 28 17:44:05 2015 +0200 @@ -202,7 +202,7 @@ notifier.fireTestStarted(testCase.name); ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream printer = new PrintStream(out); + PrintWriter printer = new PrintWriter(out); final ASTProber prober = new SLStandardASTProber(); Probe.registerASTProber(prober); try { @@ -226,6 +226,7 @@ notifier.fireTestFailure(new Failure(testCase.name, new UnsupportedOperationException("No instrumentation found."))); } + printer.flush(); String actualOutput = new String(out.toByteArray()); Assert.assertEquals(testCase.expectedOutput, actualOutput); } catch (Throwable ex) { @@ -270,15 +271,15 @@ /** * This sample listener provides prints the value of an assignment (after the assignment is - * complete) to the {@link PrintStream} specified in the constructor. This listener can only be + * complete) to the {@link PrintWriter} specified in the constructor. This listener can only be * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being * attached elsewhere. */ public final class SLPrintAssigmentValueListener extends DefaultSimpleInstrumentListener { - private PrintStream output; + private PrintWriter output; - public SLPrintAssigmentValueListener(PrintStream output) { + public SLPrintAssigmentValueListener(PrintWriter output) { this.output = output; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,1 @@ +Undefined function: foo diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,3 @@ +function main() { + foo(); +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Thu May 28 17:44:05 2015 +0200 @@ -32,8 +32,10 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.tools.*; +import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.api.vm.TruffleVM.Symbol; import com.oracle.truffle.sl.builtins.*; -import com.oracle.truffle.sl.factory.*; +import com.oracle.truffle.sl.factory.SLContextFactory; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.nodes.call.*; import com.oracle.truffle.sl.nodes.controlflow.*; @@ -42,6 +44,9 @@ import com.oracle.truffle.sl.nodes.local.*; import com.oracle.truffle.sl.parser.*; import com.oracle.truffle.sl.runtime.*; +import java.net.URI; +import java.util.Collections; +import java.util.List; /** * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as @@ -129,7 +134,20 @@ * default printer. * */ -public class SLMain { +@TruffleLanguage.Registration(name = "sl", mimeType = "application/x-sl") +public class SLMain extends TruffleLanguage { + private static SLMain LAST; + private static List> builtins = Collections.emptyList(); + private final SLContext context; + + public SLMain(Env env) { + super(env); + context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true)); + LAST = this; + for (NodeFactory builtin : builtins) { + context.installBuiltin(builtin); + } + } /* Demonstrate per-type tabulation of node execution counts */ private static boolean nodeExecCounts = false; @@ -142,29 +160,35 @@ * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup. */ public static void main(String[] args) throws IOException { - - SLContext context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), System.out); - - Source source; - if (args.length == 0) { - source = Source.fromReader(new InputStreamReader(System.in), "stdin"); - } else { - source = Source.fromFileName(args[0]); - } + TruffleVM vm = TruffleVM.newVM().build(); + assert vm.getLanguages().containsKey("application/x-sl"); int repeats = 1; if (args.length >= 2) { repeats = Integer.parseInt(args[1]); } - run(context, source, System.out, repeats); + if (args.length == 0) { + vm.eval("application/x-sl", new InputStreamReader(System.in)); + } else { + vm.eval(new File(args[0]).toURI()); + } + Symbol main = vm.findGlobalSymbol("main"); + if (main == null) { + throw new SLException("No function main() defined in SL source file."); + } + while (repeats-- > 0) { + main.invoke(null); + } } /** * Parse and run the specified SL source. Factored out in a separate method so that it can also * be used by the unit test harness. */ - public static long run(SLContext context, Source source, PrintStream logOutput, int repeats) { + public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List> currentBuiltins) throws IOException { + builtins = currentBuiltins; + if (logOutput != null) { logOutput.println("== running on " + Truffle.getRuntime().getName()); // logOutput.println("Source = " + source.getCode()); @@ -193,11 +217,14 @@ } /* Parse the SL source file. */ - Parser.parseSL(context, source); + Object result = context.eval(source); + if (result != null) { + out.println(result); + } /* Lookup our main entry point, which is per definition always named "main". */ - SLFunction main = context.getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { + Symbol main = context.findGlobalSymbol("main"); + if (main == null) { throw new SLException("No function main() defined in SL source file."); } @@ -208,19 +235,21 @@ /* Change to dump the AST to IGV over the network. */ boolean dumpASTToIGV = false; - printScript("before execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("before execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); long totalRuntime = 0; try { for (int i = 0; i < repeats; i++) { long start = System.nanoTime(); /* Call the main entry point, without any arguments. */ try { - Object result = main.getCallTarget().call(); + result = main.invoke(null); if (result != SLNull.SINGLETON) { - context.getOutput().println(result); + out.println(result); } } catch (UnsupportedSpecializationException ex) { - context.getOutput().println(formatTypeError(ex)); + out.println(formatTypeError(ex)); + } catch (SLUndefinedFunctionException ex) { + out.println(String.format("Undefined function: %s", ex.getFunctionName())); } long end = System.nanoTime(); totalRuntime += end - start; @@ -231,7 +260,7 @@ } } finally { - printScript("after execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("after execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); } if (nodeExecCounter != null) { nodeExecCounter.print(System.out); @@ -254,7 +283,7 @@ *

      * When printASTToLog is true: prints the ASTs to the console. */ - private static void printScript(String groupName, SLContext context, PrintStream logOutput, boolean printASTToLog, boolean printSourceAttributionToLog, boolean dumpASTToIGV) { + private static void printScript(String groupName, SLContext context, PrintWriter logOutput, boolean printASTToLog, boolean printSourceAttributionToLog, boolean dumpASTToIGV) { if (dumpASTToIGV) { GraphPrintVisitor graphPrinter = new GraphPrintVisitor(); graphPrinter.beginGroup(groupName); @@ -300,7 +329,7 @@ if (ex.getNode() != null && ex.getNode().getSourceSection() != null) { SourceSection ss = ex.getNode().getSourceSection(); if (ss != null && !(ss instanceof NullSourceSection)) { - result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); + result.append(" at ").append(ss.getSource().getShortName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); } } result.append(": operation"); @@ -341,4 +370,30 @@ return result.toString(); } + @Override + protected Object eval(Source code) throws IOException { + context.executeMain(code); + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + for (SLFunction f : context.getFunctionRegistry().getFunctions()) { + if (globalName.equals(f.getName())) { + return f; + } + } + return null; + } + + @Override + protected Object getLanguageGlobal() { + return context; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return object instanceof SLFunction; + } + } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java Thu May 28 17:44:05 2015 +0200 @@ -53,7 +53,7 @@ } @TruffleBoundary - private static void doPrint(PrintStream out, long value) { + private static void doPrint(PrintWriter out, long value) { out.println(value); } @@ -64,7 +64,7 @@ } @TruffleBoundary - private static void doPrint(PrintStream out, boolean value) { + private static void doPrint(PrintWriter out, boolean value) { out.println(value); } @@ -75,7 +75,7 @@ } @TruffleBoundary - private static void doPrint(PrintStream out, String value) { + private static void doPrint(PrintWriter out, String value) { out.println(value); } @@ -86,7 +86,7 @@ } @TruffleBoundary - private static void doPrint(PrintStream out, Object value) { + private static void doPrint(PrintWriter out, Object value) { out.println(value); } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Thu May 28 17:44:05 2015 +0200 @@ -52,20 +52,22 @@ StringBuilder str = new StringBuilder(); Truffle.getRuntime().iterateFrames(frameInstance -> { - dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true)); + CallTarget callTarget = frameInstance.getCallTarget(); + Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY, true); + RootNode rn = ((RootCallTarget) callTarget).getRootNode(); + if (rn.getClass().getName().contains("SLFunctionForeignAccess")) { + return 1; + } + if (str.length() > 0) { + str.append(System.getProperty("line.separator")); + } + str.append("Frame: ").append(rn.toString()); + FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); + frameDescriptor.getSlots().stream().forEach((s) -> { + str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); + }); return null; }); return str.toString(); } - - private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame) { - if (str.length() > 0) { - str.append(System.getProperty("line.separator")); - } - str.append("Frame: ").append(((RootCallTarget) callTarget).getRootNode().toString()); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - for (FrameSlot s : frameDescriptor.getSlots()) { - str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); - } - } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java Thu May 28 17:44:05 2015 +0200 @@ -32,11 +32,7 @@ private SLContextFactory() { } - public static SLContext create() { - return create(new BufferedReader(new InputStreamReader(System.in)), System.out); - } - - public static SLContext create(BufferedReader input, PrintStream output) { + public static SLContext create(BufferedReader input, PrintWriter output) { final SLContext slContext = new SLContext(input, output); slContext.setVisualizer(new SLDefaultVisualizer()); return slContext; diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java Thu May 28 17:44:05 2015 +0200 @@ -34,6 +34,11 @@ public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments); + @Specialization(guards = "function.getCallTarget() == null") + protected Object doUndefinedFunction(SLFunction function, @SuppressWarnings("unused") Object[] arguments) { + throw new SLUndefinedFunctionException(function.getName()); + } + /** * Inline cached specialization of the dispatch. * diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, 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.sl.nodes.call; + +public class SLUndefinedFunctionException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final String functionName; + + public SLUndefinedFunctionException(String functionName) { + this.functionName = functionName; + } + + public String getFunctionName() { + return functionName; + } + +} diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Thu May 28 17:44:05 2015 +0200 @@ -52,7 +52,7 @@ return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); } - @Specialization(rewriteOn = RuntimeException.class) + @Specialization protected boolean doBoolean(boolean left, boolean hasRight, boolean right) { return left || right; } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Thu May 28 17:44:05 2015 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.object.*; import com.oracle.truffle.api.source.*; -import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.builtins.*; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.nodes.local.*; @@ -50,11 +49,11 @@ private static final Layout LAYOUT = Layout.createLayout(); private final BufferedReader input; - private final PrintStream output; + private final PrintWriter output; private final SLFunctionRegistry functionRegistry; private final Shape emptyShape; - public SLContext(BufferedReader input, PrintStream output) { + public SLContext(BufferedReader input, PrintWriter output) { this.input = input; this.output = output; this.functionRegistry = new SLFunctionRegistry(); @@ -80,7 +79,7 @@ * The default default, i.e., the output for the {@link SLPrintlnBuiltin}. To allow unit * testing, we do not use {@link System#out} directly. */ - public PrintStream getOutput() { + public PrintWriter getOutput() { return output; } @@ -158,11 +157,6 @@ */ public void executeMain(Source source) { Parser.parseSL(this, source); - SLFunction main = getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { - throw new SLException("No function main() defined in SL source file."); - } - main.getCallTarget().call(); } public DynamicObject createObject() { diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Thu May 28 16:54:14 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Thu May 28 17:44:05 2015 +0200 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.runtime; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.utilities.*; /** @@ -41,7 +42,7 @@ * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name * lookup. A function that has been looked up, i.e., used, but not defined, has no call target. */ -public final class SLFunction { +public final class SLFunction implements TruffleObject { /** The name of the function. */ private final String name; @@ -90,4 +91,14 @@ public String toString() { return name; } + + /** + * In case you want some of your objects to co-operate with other languages, you need to make + * them implement {@link TruffleObject} and provide additional {@link SLFunctionForeignAccess + * foreign access implementation}. + */ + @Override + public ForeignAccessFactory getForeignAccessFactory() { + return SLFunctionForeignAccess.INSTANCE; + } } diff -r 107300758a4e -r 28cbfacd0518 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, 2014, 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.sl.runtime; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ForeignAccessFactory; +import com.oracle.truffle.api.interop.InteropPredicate; +import com.oracle.truffle.api.interop.exception.UnsupportedMessageException; +import com.oracle.truffle.api.interop.messages.Message; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.interop.ForeignAccessArguments; +import com.oracle.truffle.interop.messages.Execute; +import com.oracle.truffle.interop.messages.Receiver; +import com.oracle.truffle.sl.nodes.call.SLDispatchNode; +import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen; +import java.math.BigInteger; + +/** + * Implementation of foreing access for {@link SLFunction}. + */ +final class SLFunctionForeignAccess implements ForeignAccessFactory { + public static final ForeignAccessFactory INSTANCE = new SLFunctionForeignAccess(); + + private SLFunctionForeignAccess() { + } + + @Override + public InteropPredicate getLanguageCheck() { + return (com.oracle.truffle.api.interop.TruffleObject o) -> o instanceof SLFunction; + } + + @Override + public CallTarget getAccess(Message tree) { + if (Execute.create(Receiver.create(), 0).matchStructure(tree)) { + return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode()); + } else { + throw new UnsupportedMessageException(tree.toString() + " not supported"); + } + } + + private static class SLForeignCallerRootNode extends RootNode { + @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create(); + + @Override + public Object execute(VirtualFrame frame) { + SLFunction function = (SLFunction) ForeignAccessArguments.getReceiver(frame.getArguments()); + // the calling convention of interop passes the receiver of a + // function call (the this object) + // as an implicit 1st argument; we need to ignore this argument for SL + Object[] arguments = ForeignAccessArguments.extractUserArguments(1, frame.getArguments()); + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] instanceof Long) { + continue; + } + if (arguments[i] instanceof BigInteger) { + continue; + } + if (arguments[i] instanceof Number) { + arguments[i] = ((Number) arguments[i]).longValue(); + } + } + + return dispatch.executeDispatch(frame, function, arguments); + } + + } + +} diff -r 107300758a4e -r 28cbfacd0518 hotspot/.project --- a/hotspot/.project Thu May 28 16:54:14 2015 +0200 +++ b/hotspot/.project Thu May 28 17:44:05 2015 +0200 @@ -133,7 +133,7 @@ make 2 - WORKSPACE_LOC/make + PARENT-1-PROJECT_LOC/make solaris diff -r 107300758a4e -r 28cbfacd0518 make/defs.make --- a/make/defs.make Thu May 28 16:54:14 2015 +0200 +++ b/make/defs.make Thu May 28 17:44:05 2015 +0200 @@ -402,6 +402,8 @@ EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.truffle.PartialEvaluator EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.truffle.TruffleCompilerOptions EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.virtual.phases.ea.PartialEscapePhase +EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.lir.asm.CompilationResultBuilder +EXPORT_LIST += $(EXPORT_JRE_LIB_GRAAL_OPTIONS_DIR)/com.oracle.graal.java.GraphBuilderPhase .PHONY: $(HS_ALT_MAKE)/defs.make diff -r 107300758a4e -r 28cbfacd0518 make/linux/Makefile --- a/make/linux/Makefile Thu May 28 16:54:14 2015 +0200 +++ b/make/linux/Makefile Thu May 28 17:44:05 2015 +0200 @@ -232,7 +232,7 @@ # Solaris 2.5.1, 2.6). # Disable this check by setting DISABLE_HOTSPOT_OS_VERSION_CHECK=ok. -SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% +SUPPORTED_OS_VERSION = 2.4% 2.5% 2.6% 3% 4% OS_VERSION := $(shell uname -r) EMPTY_IF_NOT_SUPPORTED = $(filter $(SUPPORTED_OS_VERSION),$(OS_VERSION)) diff -r 107300758a4e -r 28cbfacd0518 mx/mx_graal.py --- a/mx/mx_graal.py Thu May 28 16:54:14 2015 +0200 +++ b/mx/mx_graal.py Thu May 28 17:44:05 2015 +0200 @@ -30,13 +30,13 @@ from os.path import join, exists, dirname, basename from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER from outputparser import OutputParser, ValuesMatcher -import hashlib import mx import xml.dom.minidom import sanitycheck import itertools import json, textwrap import fnmatch +import mx_graal_makefile # This works because when mx loads this file, it makes sure __file__ gets an absolute path _graal_home = dirname(dirname(__file__)) @@ -1559,7 +1559,6 @@ parser = ArgumentParser(prog='mx ctw') parser.add_argument('--ctwopts', action='store', help='space separated Graal options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='') parser.add_argument('--jar', action='store', help='jar of classes to compiled instead of rt.jar', metavar='') - parser.add_argument('vmargs', nargs=REMAINDER, metavar='VM options...') args, vmargs = parser.parse_known_args(args) @@ -1640,6 +1639,12 @@ vm(['-XX:-TieredCompilation', '-G:RegisterPressure=' + registers, '-esa', '-version']) with VM('graal', 'product'): + with Task('BootstrapSSAWithRegisterPressure:product', tasks) as t: + if t: + registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if platform.processor() == 'sparc' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14' + vm(['-XX:-TieredCompilation', '-G:+SSA_LIR', '-G:RegisterPressure=' + registers, '-esa', '-version']) + + with VM('graal', 'product'): with Task('BootstrapWithImmutableCode:product', tasks) as t: if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) @@ -1700,6 +1705,7 @@ parser = ArgumentParser(prog='mx gate') parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code') parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code') + parser.add_argument('-i', '--omit-ide-clean', action='store_false', dest='cleanIde', help='omit cleaning the ide project files') parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM') parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run') parser.add_argument('--jacocout', help='specify the output directory for jacoco report') @@ -1732,10 +1738,11 @@ clean(cleanArgs) _clean() - with Task('IDEConfigCheck', tasks): + with Task('IDEConfigCheck', tasks) as t: if t: - mx.ideclean([]) - mx.ideinit([]) + if args.cleanIde: + mx.ideclean([]) + mx.ideinit([]) eclipse_exe = mx.get_env('ECLIPSE_EXE') if eclipse_exe is not None: @@ -2602,6 +2609,7 @@ 'longtests' : [longtests, ''], 'sl' : [sl, '[SL args|@VM options]'], 'jol' : [jol, ''], + 'makefile' : [mx_graal_makefile.build_makefile, 'build makefiles for JDK build'], } mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) diff -r 107300758a4e -r 28cbfacd0518 mx/mx_graal_makefile.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mx/mx_graal_makefile.py Thu May 28 17:44:05 2015 +0200 @@ -0,0 +1,184 @@ +import mx, os, sys +# +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2015, 2015, 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. +# +# ---------------------------------------------------------------------------------------------------- +# + + +def build_makefile(args): + """Build a Makefile from the suitte.py to build graa.jar without python""" + if len(args) == 0 or args[0] == "-": + do_build_makefile(lambda l: sys.stdout.write(l + os.linesep)) + elif args[0] == "-o": + with open(args[1], "w") as f: + do_build_makefile(lambda l: f.write(l + os.linesep)) + +def relative_dep_path(d): + if isinstance(d, str): d = mx.dependency(d) + return os.path.basename(d.get_path(False)) + +def createMakeRule(p, bootClasspath): + def filterDeps(deps, t): + def typeFilter(project): # filters + if isinstance(project, str): + project = mx.dependency(project, True) + return isinstance(project, t) + return [d for d in deps if typeFilter(d)] + + + canonicalDeps = p.canonical_deps() + canonicalProjectDep = filterDeps(canonicalDeps, mx.Project) + canonicalProjectDepDirs = ['$(TARGET)/' +i for i in canonicalProjectDep] + canonicalLibDep = filterDeps(canonicalDeps, mx.Library) + canonicalLibDepJars = ["$(LIB)/" + relative_dep_path(d) for d in canonicalLibDep] + + allDep = p.all_deps([], True, False, includeAnnotationProcessors=True) + allProcessorDistNames = [x.definedAnnotationProcessorsDist.name for x in filterDeps(allDep, mx.Project) if x.definedAnnotationProcessors != None] + allProjectDep = filterDeps(allDep, mx.Project) + allProjectDepDir = ['$(TARGET)/' +i.name for i in allProjectDep] + allLibDep = filterDeps(allDep, mx.Library) + allLibDepJar = ["$(LIB)/" + relative_dep_path(d) for d in allLibDep] + + processor = p.annotation_processors_path() + if processor != None: processor = processor.replace(p.suite.dir, "$(TARGET)") + + cp = allLibDepJar +allProjectDepDir + props = { + 'name': p.name, + 'project_deps': ' '.join(canonicalProjectDepDirs + canonicalLibDepJars + allProcessorDistNames), + 'cp_deps': ('-cp ' + ':'.join(cp)) if len(cp) > 0 else '', + 'cp_boot': ('-bootclasspath ' + bootClasspath) if len(bootClasspath) > 0 else '', + 'processor': ('-processorpath ' + processor) if processor != None else '' + } + return """$(TARGET)/{name}: $(shell find graal/{name}/src/ -type f -name *.java) {project_deps} +\t$(eval TMP := $(shell mktemp -d)) +\ttest ! -d $(TARGET)/{name} || cp -Rp $(TARGET)/{name} $(TMP) +\t$(JAVAC) -d $(TMP) {cp_boot} {processor} {cp_deps} $(shell find graal/{name}/src/ -type f -name *.java) +\ttest ! -d graal/{name}/src/META-INF || (mkdir -p $(TARGET)/{name}/META-INF/ && cp -r graal/{name}/src/META-INF/ $(TARGET)/{name}/) +\tmkdir -p $(TARGET)/{name} +\tcp -r $(TMP)/* $(TARGET)/{name} +\ttouch $(TARGET)/{name} +\trm -r $(TMP) +""".format(**props) + +def createDistributionRule(dist): + sorted_deps = set(dist.sorted_deps(False, True)) + depDirs = ' '.join(['$(TARGET)/' + i.name for i in sorted_deps]) + depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in sorted_deps]) + jarPath = os.path.relpath(dist.path, dist.suite.dir) + jarDir = os.path.dirname(jarPath) + props = { + 'dist_name': dist.name, + 'depDirs': depDirs, + 'depDirsStar': depDirsStar, + 'jar_path': jarPath, + 'jar_dir': jarDir, + 'providers_dir': '$(TMP)/META-INF/providers/ ', + 'services_dir': '$(TMP)/META-INF/services/' + } + return """{dist_name}: {depDirs} +\t$(eval TMP := $(shell mktemp -d)) +\tmkdir -p $(TARGET){jar_dir} +\ttouch $(TARGET)/{jar_path} +\tcp -r {depDirsStar} $(TMP) +\ttest -d {services_dir} || mkdir -p {services_dir} +\ttest ! -d {providers_dir} || (cd {providers_dir} && for i in $$(ls); do c=$$(cat $$i); echo $$i >> {services_dir}$$c; done) +\ttest ! -d {providers_dir} || rm -r {providers_dir} +\t$(JAR) cvf $(TARGET){jar_path} -C $(TMP) . +\trm -r $(TMP) +""".format(**props) + +def createDownloadRule(lib): + http_urls = [u for u in lib.urls if u.startswith("http")] + if len(http_urls) == 0: http_urls = [u for u in lib.urls if u.startswith("jar")] + if len(http_urls) == 0: raise BaseException("No http url specified for downloading library %s: available urls: %s" % (lib.name, lib.urls)) + url = http_urls[0] + tofile = '$(LIB)/' + relative_dep_path(lib) + if url.startswith("jar"): + props = { + 'url': url[url.find(":")+1:url.rfind("!")], + 'archive_file': url[url.rfind("!")+1:], + 'dest': tofile + } + dl = """\t$(eval TMP := $(shell mktemp -d)) +\tcd $(TMP) && $(WGET) -O dl.zip {url} && $(JAR) xf dl.zip +\tmv $(TMP)/{archive_file} {dest} +\trm -rf $(TMP)""".format(**props) + else: + dl = "\t$(WGET) -O {} {}".format(tofile, url) + return """{}:\n{}""".format(tofile, dl) + + +def create_suite_build(suite, out): + for p in suite.projects: + java = mx.java(p.javaCompliance) + bootClassPath = java.bootclasspath() + bootClassPath = bootClassPath.replace(java.jdk, "$(JDK)") + out(createMakeRule(p, bootClassPath)) + for l in suite.libs: + out(createDownloadRule(l)) + + distributionNames = [] + for d in suite.dists: + distributionNames.append(d.name) + out(createDistributionRule(d)) + out("{0}: {1}\n.PHONY: {1}".format(suite.name, " ".join(distributionNames))) + + +def do_build_makefile(out): + out("""VERBOSE= +TARGET=build/ +LIB=$(TARGET)/lib +JDK= + +WGET=wget +JAVAC=$(JDK)/bin/javac +JAR=$(JDK)/bin/jar + + +ifeq ($(JDK),) +$(error Variable JDK must be set to a JDK installation.) +endif +ifneq ($(VERBOSE),) +SHELL=sh -x +endif + +all: default + +$(TARGET): +\tmkdir -p $(TARGET) + +$(LIB): +\tmkdir -p $(LIB) +""") + suiteNames = [] + for s in mx.suites(): + suiteNames.append(s.name) + create_suite_build(s, out) + + out("""default: $(TARGET) $(LIB) {0} +.PHONY: {0} + """.format(" ".join(suiteNames))) + diff -r 107300758a4e -r 28cbfacd0518 mx/sanitycheck.py --- a/mx/sanitycheck.py Thu May 28 16:54:14 2015 +0200 +++ b/mx/sanitycheck.py Thu May 28 17:44:05 2015 +0200 @@ -219,7 +219,8 @@ dacapoMatcher = ValuesMatcher(dacapoTime, {'group' : 'DaCapo', 'name' : '', 'score' : '