# HG changeset patch # User Christian Haeubl # Date 1368457891 -7200 # Node ID f9a65a0e626b5b80ffda62db61c82fda96f730e1 # Parent 57113d21ce3619a6432888f777227a01cd269b9b# Parent 822adbb2ee7b38a95078a067172bc49c6a247820 Merge. diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java --- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java Mon May 13 17:11:31 2013 +0200 @@ -23,12 +23,12 @@ package com.oracle.graal.amd64; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.code.Register.RegisterFlag.*; +import static com.oracle.graal.api.code.Register.*; import java.nio.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Register.RegisterFlag; +import com.oracle.graal.api.code.Register.RegisterCategory; import com.oracle.graal.api.meta.*; /** @@ -36,26 +36,29 @@ */ public class AMD64 extends Architecture { + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + public static final RegisterCategory XMM = new RegisterCategory("XMM"); + // @formatter:off // General purpose CPU registers - public static final Register rax = new Register(0, 0, 8, "rax", CPU, RegisterFlag.Byte); - public static final Register rcx = new Register(1, 1, 8, "rcx", CPU, RegisterFlag.Byte); - public static final Register rdx = new Register(2, 2, 8, "rdx", CPU, RegisterFlag.Byte); - public static final Register rbx = new Register(3, 3, 8, "rbx", CPU, RegisterFlag.Byte); - public static final Register rsp = new Register(4, 4, 8, "rsp", CPU, RegisterFlag.Byte); - public static final Register rbp = new Register(5, 5, 8, "rbp", CPU, RegisterFlag.Byte); - public static final Register rsi = new Register(6, 6, 8, "rsi", CPU, RegisterFlag.Byte); - public static final Register rdi = new Register(7, 7, 8, "rdi", CPU, RegisterFlag.Byte); + public static final Register rax = new Register(0, 0, "rax", CPU); + public static final Register rcx = new Register(1, 1, "rcx", CPU); + public static final Register rdx = new Register(2, 2, "rdx", CPU); + public static final Register rbx = new Register(3, 3, "rbx", CPU); + public static final Register rsp = new Register(4, 4, "rsp", CPU); + public static final Register rbp = new Register(5, 5, "rbp", CPU); + public static final Register rsi = new Register(6, 6, "rsi", CPU); + public static final Register rdi = new Register(7, 7, "rdi", CPU); - public static final Register r8 = new Register(8, 8, 8, "r8", CPU, RegisterFlag.Byte); - public static final Register r9 = new Register(9, 9, 8, "r9", CPU, RegisterFlag.Byte); - public static final Register r10 = new Register(10, 10, 8, "r10", CPU, RegisterFlag.Byte); - public static final Register r11 = new Register(11, 11, 8, "r11", CPU, RegisterFlag.Byte); - public static final Register r12 = new Register(12, 12, 8, "r12", CPU, RegisterFlag.Byte); - public static final Register r13 = new Register(13, 13, 8, "r13", CPU, RegisterFlag.Byte); - public static final Register r14 = new Register(14, 14, 8, "r14", CPU, RegisterFlag.Byte); - public static final Register r15 = new Register(15, 15, 8, "r15", CPU, RegisterFlag.Byte); + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); public static final Register[] cpuRegisters = { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, @@ -63,23 +66,23 @@ }; // XMM registers - public static final Register xmm0 = new Register(16, 0, 8, "xmm0", FPU); - public static final Register xmm1 = new Register(17, 1, 8, "xmm1", FPU); - public static final Register xmm2 = new Register(18, 2, 8, "xmm2", FPU); - public static final Register xmm3 = new Register(19, 3, 8, "xmm3", FPU); - public static final Register xmm4 = new Register(20, 4, 8, "xmm4", FPU); - public static final Register xmm5 = new Register(21, 5, 8, "xmm5", FPU); - public static final Register xmm6 = new Register(22, 6, 8, "xmm6", FPU); - public static final Register xmm7 = new Register(23, 7, 8, "xmm7", FPU); + public static final Register xmm0 = new Register(16, 0, "xmm0", XMM); + public static final Register xmm1 = new Register(17, 1, "xmm1", XMM); + public static final Register xmm2 = new Register(18, 2, "xmm2", XMM); + public static final Register xmm3 = new Register(19, 3, "xmm3", XMM); + public static final Register xmm4 = new Register(20, 4, "xmm4", XMM); + public static final Register xmm5 = new Register(21, 5, "xmm5", XMM); + public static final Register xmm6 = new Register(22, 6, "xmm6", XMM); + public static final Register xmm7 = new Register(23, 7, "xmm7", XMM); - public static final Register xmm8 = new Register(24, 8, 8, "xmm8", FPU); - public static final Register xmm9 = new Register(25, 9, 8, "xmm9", FPU); - public static final Register xmm10 = new Register(26, 10, 8, "xmm10", FPU); - public static final Register xmm11 = new Register(27, 11, 8, "xmm11", FPU); - public static final Register xmm12 = new Register(28, 12, 8, "xmm12", FPU); - public static final Register xmm13 = new Register(29, 13, 8, "xmm13", FPU); - public static final Register xmm14 = new Register(30, 14, 8, "xmm14", FPU); - public static final Register xmm15 = new Register(31, 15, 8, "xmm15", FPU); + public static final Register xmm8 = new Register(24, 8, "xmm8", XMM); + public static final Register xmm9 = new Register(25, 9, "xmm9", XMM); + public static final Register xmm10 = new Register(26, 10, "xmm10", XMM); + public static final Register xmm11 = new Register(27, 11, "xmm11", XMM); + public static final Register xmm12 = new Register(28, 12, "xmm12", XMM); + public static final Register xmm13 = new Register(29, 13, "xmm13", XMM); + public static final Register xmm14 = new Register(30, 14, "xmm14", XMM); + public static final Register xmm15 = new Register(31, 15, "xmm15", XMM); public static final Register[] xmmRegisters = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, @@ -96,7 +99,7 @@ /** * Register used to construct an instruction-relative address. */ - public static final Register rip = new Register(32, -1, 0, "rip"); + public static final Register rip = new Register(32, -1, "rip", SPECIAL); public static final Register[] allRegisters = { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, @@ -124,54 +127,6 @@ } // @formatter:on - @Override - public int getMaxVectorLength(Kind kind) { - if (supportedAVXVersion > 0) { - switch (kind) { - case Boolean: - return 32; - case Byte: - return 32; - case Short: - return 16; - case Char: - return 16; - case Int: - return 8; - case Float: - return 8; - case Long: - return 4; - case Double: - return 4; - case Object: - return 4; - } - } else { - switch (kind) { - case Boolean: - return 16; - case Byte: - return 16; - case Short: - return 8; - case Char: - return 8; - case Int: - return 4; - case Float: - return 4; - case Long: - return 2; - case Double: - return 2; - case Object: - return 2; - } - } - return 1; - } - public int getSupportedSSEVersion() { return supportedSSEVersion; } @@ -179,4 +134,44 @@ public int getSupportedAVXVersion() { return supportedAVXVersion; } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + if (!(platformKind instanceof Kind)) { + return false; + } + + Kind kind = (Kind) platformKind; + if (category == CPU) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return true; + } + } else if (category == XMM) { + switch (kind) { + case Float: + case Double: + return true; + } + } + + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category == CPU) { + return Kind.Long; + } else if (category == XMM) { + return Kind.Double; + } else { + return Kind.Illegal; + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Mon May 13 17:11:31 2013 +0200 @@ -24,6 +24,7 @@ import java.nio.*; +import com.oracle.graal.api.code.Register.RegisterCategory; import com.oracle.graal.api.meta.*; /** @@ -164,4 +165,40 @@ public int getMaxVectorLength(@SuppressWarnings("unused") Kind kind) { return 1; } + + /** + * Gets the size in bytes of the specified kind for this target. + * + * @param kind the kind for which to get the size + * + * @return the size in bytes of {@code kind} + */ + public int getSizeInBytes(PlatformKind kind) { + switch ((Kind) kind) { + case Boolean: + return 1; + case Byte: + return 1; + case Char: + return 2; + case Short: + return 2; + case Int: + return 4; + case Long: + return 8; + case Float: + return 4; + case Double: + return 8; + case Object: + return wordSize; + default: + return 0; + } + } + + public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind); + + public abstract PlatformKind getLargestStorableKind(RegisterCategory category); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java Mon May 13 17:11:31 2013 +0200 @@ -24,6 +24,8 @@ import java.util.*; +import com.oracle.graal.api.meta.*; + /** * The callee save area (CSA) is a contiguous space in a stack frame used to save (and restore) the * values of the caller's registers. This class describes the layout of a CSA in terms of its @@ -69,7 +71,7 @@ * CSA * @param registers the registers that can be saved in the CSA */ - public CalleeSaveLayout(int frameOffsetToCSA, int size, int slotSize, Register... registers) { + public CalleeSaveLayout(Architecture architecture, int frameOffsetToCSA, int size, int slotSize, Register... registers) { this.frameOffsetToCSA = frameOffsetToCSA; assert slotSize == 0 || CodeUtil.isPowerOf2(slotSize); this.slotSize = slotSize; @@ -86,7 +88,8 @@ if (offset > maxOffset) { maxOffset = offset; } - offset += reg.spillSlotSize; + PlatformKind kind = architecture.getLargestStorableKind(reg.getRegisterCategory()); + offset += architecture.getSizeInBytes(kind); } if (size == -1) { this.size = offset; @@ -103,7 +106,8 @@ int index = offset / slotSize; regNumToIndex[reg.number] = index; indexToReg[index] = reg; - offset += reg.spillSlotSize; + PlatformKind kind = architecture.getLargestStorableKind(reg.getRegisterCategory()); + offset += architecture.getSizeInBytes(kind); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java Mon May 13 17:11:31 2013 +0200 @@ -171,7 +171,7 @@ sb.append(sep).append(op); sep = ", "; } - if (returnLocation != Value.ILLEGAL) { + if (!returnLocation.equals(Value.ILLEGAL)) { sb.append(" -> ").append(returnLocation); } if (temporaryLocations.length != 0) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Mon May 13 17:11:31 2013 +0200 @@ -303,6 +303,14 @@ } sb.append(' ').append(bm).append(nl); } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append("callee-save-info:").append(nl); + Map map = calleeSaveInfo.slotsToRegisters(true); + for (Map.Entry e : map.entrySet()) { + sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl); + } + } BytecodeFrame frame = info.frame(); if (frame != null) { append(sb, frame); @@ -318,9 +326,17 @@ public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) { Signature sig = method.getSignature(); JavaType retType = sig.getReturnType(null); - JavaType[] argTypes = new JavaType[sig.getParameterCount(!Modifier.isStatic(method.getModifiers()))]; - for (int i = 0; i < argTypes.length; i++) { - argTypes[i] = sig.getParameterType(i, null); + int sigCount = sig.getParameterCount(false); + JavaType[] argTypes; + int argIndex = 0; + if (!Modifier.isStatic(method.getModifiers())) { + argTypes = new JavaType[sigCount + 1]; + argTypes[argIndex++] = method.getDeclaringClass(); + } else { + argTypes = new JavaType[sigCount]; + } + for (int i = 0; i < sigCount; i++) { + argTypes[argIndex++] = sig.getParameterType(i, null); } RegisterConfig registerConfig = codeCache.lookupRegisterConfig(); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Mon May 13 17:11:31 2013 +0200 @@ -507,6 +507,16 @@ if (info != null) { appendRefMap(sb, "stackMap", info.getFrameRefMap()); appendRefMap(sb, "registerMap", info.getRegisterRefMap()); + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append(" callee-save-info["); + String sep = ""; + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); + sep = ", "; + } + sb.append(']'); + } BytecodePosition codePos = info.getBytecodePosition(); if (codePos != null) { MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Mon May 13 17:11:31 2013 +0200 @@ -26,8 +26,16 @@ import java.util.*; /** - * Represents the debugging information for a particular place in the code, which includes the code - * position, a reference map, and deoptimization information. + * Represents the debugging information for a particular point of execution. This information + * includes: + *
    + *
  • a {@linkplain #getBytecodePosition() bytecode position}
  • + *
  • a reference map for {@linkplain #getRegisterRefMap() registers}
  • + *
  • a reference map for {@linkplain #getRegisterRefMap() stack slots} in the current frame
  • + *
  • a map from bytecode locals and operand stack slots to their values or locations from which + * their values can be read
  • + *
  • a map from the registers (in the caller's frame) to the slots where they are saved in the + * current frame
  • */ public class DebugInfo implements Serializable { @@ -37,6 +45,7 @@ private final BitSet registerRefMap; private final BitSet frameRefMap; private final short deoptimizationReason; + private RegisterSaveLayout calleeSaveInfo; /** * Creates a new {@link DebugInfo} from the given values. @@ -125,4 +134,20 @@ public short getDeoptimizationReason() { return deoptimizationReason; } + + /** + * Sets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. + */ + public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) { + this.calleeSaveInfo = calleeSaveInfo; + } + + /** + * Gets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. If no such information is available, {@code null} is returned. + */ + public RegisterSaveLayout getCalleeSaveInfo() { + return calleeSaveInfo; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java Mon May 13 17:11:31 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.api.code; import java.io.*; -import java.util.*; import com.oracle.graal.api.meta.*; @@ -34,18 +33,20 @@ private static final long serialVersionUID = -7213269157816016300L; + public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL"); + /** * Invalid register. */ - public static final Register None = new Register(-1, -1, 0, "noreg"); + public static final Register None = new Register(-1, -1, "noreg", SPECIAL); /** * Frame pointer of the current method. All spill slots and outgoing stack-based arguments are * addressed relative to this register. */ - public static final Register Frame = new Register(-2, -2, 0, "framereg", RegisterFlag.CPU); + public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL); - public static final Register CallerFrame = new Register(-3, -3, 0, "callerframereg", RegisterFlag.CPU); + public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL); /** * The identifier for this register that is unique across all the registers in a @@ -72,42 +73,40 @@ } /** - * The size of the stack slot used to spill the value of this register. - */ - public final int spillSlotSize; - - /** - * The set of {@link RegisterFlag} values associated with this register. + * A platform specific register category that describes which values can be stored in a + * register. */ - private final int flags; - - /** - * An array of {@link RegisterValue} objects, for this register, with one entry per {@link Kind} - * , indexed by {@link Kind#ordinal}. - */ - private final RegisterValue[] values; + private final RegisterCategory registerCategory; /** - * Attributes that characterize a register in a useful way. - * + * A platform specific register type that describes which values can be stored in a register. */ - public enum RegisterFlag { - /** - * Denotes an integral (i.e. non floating point) register. - */ - CPU, + public static class RegisterCategory { + + private String name; + + public RegisterCategory(String name) { + this.name = name; + } - /** - * Denotes a register whose lowest order byte can be addressed separately. - */ - Byte, + @Override + public String toString() { + return name; + } - /** - * Denotes a floating point register. - */ - FPU; + @Override + public int hashCode() { + return 23 + name.hashCode(); + } - public final int mask = 1 << (ordinal() + 1); + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterCategory) { + RegisterCategory other = (RegisterCategory) obj; + return name.equals(other.name); + } + return false; + } } /** @@ -115,33 +114,18 @@ * * @param number unique identifier for the register * @param encoding the target machine encoding for the register - * @param spillSlotSize the size of the stack slot used to spill the value of the register * @param name the mnemonic name for the register - * @param flags the set of {@link RegisterFlag} values for the register + * @param registerCategory the register category */ - public Register(int number, int encoding, int spillSlotSize, String name, RegisterFlag... flags) { + public Register(int number, int encoding, String name, RegisterCategory registerCategory) { this.number = number; this.name = name; - this.spillSlotSize = spillSlotSize; - this.flags = createMask(flags); + this.registerCategory = registerCategory; this.encoding = encoding; - - values = new RegisterValue[Kind.values().length]; - for (Kind kind : Kind.values()) { - values[kind.ordinal()] = new RegisterValue(kind, this); - } } - private static int createMask(RegisterFlag... flags) { - int result = 0; - for (RegisterFlag f : flags) { - result |= f.mask; - } - return result; - } - - public boolean isSet(RegisterFlag f) { - return (flags & f.mask) != 0; + public RegisterCategory getRegisterCategory() { + return registerCategory; } /** @@ -150,8 +134,8 @@ * @param kind the specified kind * @return the {@link RegisterValue} */ - public RegisterValue asValue(Kind kind) { - return values[kind.ordinal()]; + public RegisterValue asValue(PlatformKind kind) { + return new RegisterValue(kind, this); } /** @@ -173,60 +157,6 @@ } /** - * Determines if this a floating point register. - */ - public boolean isFpu() { - return isSet(RegisterFlag.FPU); - } - - /** - * Determines if this a general purpose register. - */ - public boolean isCpu() { - return isSet(RegisterFlag.CPU); - } - - /** - * Determines if this register has the {@link RegisterFlag#Byte} attribute set. - * - * @return {@code true} iff this register has the {@link RegisterFlag#Byte} attribute set. - */ - public boolean isByte() { - return isSet(RegisterFlag.Byte); - } - - /** - * Gets a hash code for this register. - * - * @return the value of {@link #number} - */ - @Override - public int hashCode() { - return number; - } - - /** - * Categorizes a set of registers by {@link RegisterFlag}. - * - * @param registers a list of registers to be categorized - * @return a map from each {@link RegisterFlag} constant to the list of registers for which the - * flag is {@linkplain #isSet(RegisterFlag) set} - */ - public static EnumMap categorize(Register[] registers) { - EnumMap result = new EnumMap<>(RegisterFlag.class); - for (RegisterFlag flag : RegisterFlag.values()) { - ArrayList list = new ArrayList<>(); - for (Register r : registers) { - if (r.isSet(flag)) { - list.add(r); - } - } - result.put(flag, list.toArray(new Register[list.size()])); - } - return result; - } - - /** * Gets the maximum register {@linkplain #number number} in a given set of registers. * * @param registers the set of registers to process @@ -274,4 +204,23 @@ return 0; } + @Override + public int hashCode() { + final int prime = 17; + int result = 1; + result = prime * result + encoding; + result = prime * result + name.hashCode(); + result = prime * result + number; + result = prime * result + registerCategory.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Register) { + Register other = (Register) obj; + return encoding == other.encoding && name.equals(other.name) && number == other.number && registerCategory.equals(registerCategory); + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Mon May 13 17:11:31 2013 +0200 @@ -22,10 +22,7 @@ */ package com.oracle.graal.api.code; -import java.util.*; - -import com.oracle.graal.api.code.CallingConvention.*; -import com.oracle.graal.api.code.Register.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; /** @@ -60,12 +57,11 @@ * given calling convention. * * @param type the type of calling convention - * @param flag specifies whether registers for {@linkplain RegisterFlag#CPU integral} or - * {@linkplain RegisterFlag#FPU floating point} parameters are being requested + * @param kind specifies what kind of registers is being requested * @return the ordered set of registers that may be used to pass parameters in a call conforming * to {@code type} */ - Register[] getCallingConventionRegisters(Type type, RegisterFlag flag); + Register[] getCallingConventionRegisters(Type type, Kind kind); /** * Gets the set of registers that can be used by the register allocator. @@ -73,16 +69,10 @@ Register[] getAllocatableRegisters(); /** - * Gets the set of registers that can be used by the register allocator, - * {@linkplain Register#categorize(Register[]) categorized} by register - * {@linkplain RegisterFlag flags}. - * - * @return a map from each {@link RegisterFlag} constant to the list of - * {@linkplain #getAllocatableRegisters() allocatable} registers for which the flag is - * set - * + * Gets the set of registers that can be used by the register allocator for a value of a + * particular kind. */ - EnumMap getCategorizedAllocatableRegisters(); + Register[] getAllocatableRegisters(PlatformKind kind); /** * Gets the registers whose values must be preserved by a method across any call it makes. @@ -102,7 +92,6 @@ * * @return an array where an element at index i holds the attributes of the register whose * number is i - * @see Register#categorize(Register[]) */ RegisterAttributes[] getAttributesMap(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.code; + +import java.util.*; + +/** + * A map from registers to frame slots. This can be used to describe where callee saved registers + * are saved in a callee's frame. + */ +public class RegisterSaveLayout { + + /** + * Keys. + */ + private Register[] registers; + + /** + * Slot indexes relative to stack pointer. + */ + private int[] slots; + + /** + * Creates a map from registers to frame slots. + * + * @param registers the keys in the map + * @param slots frame slot index for each register in {@code registers} + */ + public RegisterSaveLayout(Register[] registers, int[] slots) { + assert registers.length == slots.length; + this.registers = registers; + this.slots = slots; + assert registersToSlots(false).size() == registers.length : "non-unique registers"; + assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots"; + } + + /** + * Gets this layout information as a {@link Map} from registers to slots. + */ + public Map registersToSlots(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(registers[i], slots[i]); + } + return result; + } + + /** + * Gets this layout information as a {@link Map} from slots to registers. + */ + public Map slotsToRegisters(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(slots[i], registers[i]); + } + return result; + } + + @Override + public String toString() { + return registersToSlots(true).toString(); + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Mon May 13 17:11:31 2013 +0200 @@ -27,8 +27,8 @@ /** * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance * of {@link RegisterValue} for each ({@link Register}, {@link Kind}) pair. Use - * {@link Register#asValue(Kind)} to retrieve the canonical {@link RegisterValue} instance for a - * given (register,kind) pair. + * {@link Register#asValue(PlatformKind)} to retrieve the canonical {@link RegisterValue} instance + * for a given (register,kind) pair. */ public final class RegisterValue extends AllocatableValue { @@ -39,17 +39,12 @@ /** * Should only be called from {@link Register#Register} to ensure canonicalization. */ - protected RegisterValue(Kind kind, Register register) { + protected RegisterValue(PlatformKind kind, Register register) { super(kind); this.reg = register; } @Override - public int hashCode() { - return (getRegister().number << 4) ^ getKind().ordinal(); - } - - @Override public String toString() { return getRegister().name + getKindSuffix(); } @@ -60,4 +55,18 @@ public Register getRegister() { return reg; } + + @Override + public int hashCode() { + return 29 * super.hashCode() + reg.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterValue) { + RegisterValue other = (RegisterValue) obj; + return super.equals(obj) && reg.equals(other.reg); + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Mon May 13 17:11:31 2013 +0200 @@ -67,14 +67,14 @@ /** * Gets the return kind of this runtime call. */ - public Class getResultType() { + public Class getResultType() { return resultType; } /** * Gets the argument kinds of this runtime call. */ - public Class[] getArgumentTypes() { + public Class[] getArgumentTypes() { return argumentTypes.clone(); } @@ -115,5 +115,11 @@ Descriptor getDescriptor(); - boolean preservesRegisters(); + /** + * Determines if the target routine destroys all registers. + * + * @return {@code true} if the register allocator must save all live registers around a call to + * this target + */ + boolean destroysRegisters(); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.api.code; -import static com.oracle.graal.api.meta.Kind.*; - import com.oracle.graal.api.meta.*; /** @@ -46,36 +44,16 @@ * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the * beginning of the frame (stack pointer + total frame size). */ - public static StackSlot get(Kind kind, int offset, boolean addFrameSize) { - assert kind.getStackKind() == kind; + public static StackSlot get(PlatformKind kind, int offset, boolean addFrameSize) { assert addFrameSize || offset >= 0; - - if (offset % CACHE_GRANULARITY == 0) { - StackSlot[][] cache; - int index = offset / CACHE_GRANULARITY; - if (!addFrameSize) { - cache = OUT_CACHE; - } else if (offset >= 0) { - cache = IN_CACHE; - } else { - cache = SPILL_CACHE; - index = -index; - } - StackSlot[] slots = cache[kind.ordinal()]; - if (index < slots.length) { - StackSlot slot = slots[index]; - assert slot.getKind() == kind && slot.offset == offset && slot.addFrameSize == addFrameSize; - return slot; - } - } return new StackSlot(kind, offset, addFrameSize); } /** - * Private constructor to enforce use of {@link #get(Kind, int, boolean)} so that a cache can be - * used. + * Private constructor to enforce use of {@link #get(PlatformKind, int, boolean)} so that a + * cache can be used. */ - private StackSlot(Kind kind, int offset, boolean addFrameSize) { + private StackSlot(PlatformKind kind, int offset, boolean addFrameSize) { super(kind); this.offset = offset; this.addFrameSize = addFrameSize; @@ -106,23 +84,6 @@ } @Override - public int hashCode() { - return getKind().ordinal() ^ (offset << 4) ^ (addFrameSize ? 15 : 0); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (o instanceof StackSlot) { - StackSlot l = (StackSlot) o; - return l.getKind() == getKind() && l.offset == offset && l.addFrameSize == addFrameSize; - } - return false; - } - - @Override public String toString() { if (!addFrameSize) { return "out:" + offset + getKindSuffix(); @@ -139,7 +100,7 @@ public StackSlot asOutArg() { assert offset >= 0; if (addFrameSize) { - return get(getKind(), offset, false); + return get(getPlatformKind(), offset, false); } return this; } @@ -150,28 +111,26 @@ public StackSlot asInArg() { assert offset >= 0; if (!addFrameSize) { - return get(getKind(), offset, true); + return get(getPlatformKind(), offset, true); } return this; } - private static final int CACHE_GRANULARITY = 8; - private static final int SPILL_CACHE_PER_KIND_SIZE = 100; - private static final int PARAM_CACHE_PER_KIND_SIZE = 10; - - private static final StackSlot[][] SPILL_CACHE = makeCache(SPILL_CACHE_PER_KIND_SIZE, -1, true); - private static final StackSlot[][] IN_CACHE = makeCache(PARAM_CACHE_PER_KIND_SIZE, 1, true); - private static final StackSlot[][] OUT_CACHE = makeCache(PARAM_CACHE_PER_KIND_SIZE, 1, false); + @Override + public int hashCode() { + final int prime = 37; + int result = super.hashCode(); + result = prime * result + (addFrameSize ? 1231 : 1237); + result = prime * result + offset; + return result; + } - private static StackSlot[][] makeCache(int cachePerKindSize, int sign, boolean addFrameSize) { - StackSlot[][] cache = new StackSlot[Kind.values().length][]; - for (Kind kind : new Kind[]{Illegal, Int, Long, Float, Double, Object}) { - StackSlot[] slots = new StackSlot[cachePerKindSize]; - for (int i = 0; i < cachePerKindSize; i++) { - slots[i] = new StackSlot(kind, sign * i * CACHE_GRANULARITY, addFrameSize); - } - cache[kind.ordinal()] = slots; + @Override + public boolean equals(Object obj) { + if (obj instanceof StackSlot) { + StackSlot other = (StackSlot) obj; + return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset; } - return cache; + return false; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java Mon May 13 17:11:31 2013 +0200 @@ -83,39 +83,6 @@ } /** - * Gets the size in bytes of the specified kind for this target. - * - * @param kind the kind for which to get the size - * @return the size in bytes of {@code kind} - */ - public int sizeInBytes(Kind kind) { - // Checkstyle: stop - switch (kind) { - case Boolean: - return 1; - case Byte: - return 1; - case Char: - return 2; - case Short: - return 2; - case Int: - return 4; - case Long: - return 8; - case Float: - return 4; - case Double: - return 8; - case Object: - return wordSize; - default: - return 0; - } - // Checkstyle: resume - } - - /** * Aligns the given frame size (without return instruction pointer) to the stack alignment size * and return the aligned size (without return instruction pointer). * diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Mon May 13 17:11:31 2013 +0200 @@ -31,7 +31,7 @@ public static boolean isIllegal(Value value) { assert value != null; - return value == Value.ILLEGAL; + return value.equals(Value.ILLEGAL); } public static boolean isLegal(Value value) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Mon May 13 17:11:31 2013 +0200 @@ -168,7 +168,7 @@ @Override public int hashCode() { - return getKind().ordinal() + type.hashCode(); + return getPlatformKind().hashCode() + type.hashCode(); } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AllocatableValue.java Mon May 13 17:11:31 2013 +0200 @@ -32,8 +32,7 @@ public static final AllocatableValue[] NONE = {}; - public AllocatableValue(Kind kind) { - super(kind); + public AllocatableValue(PlatformKind platformKind) { + super(platformKind); } - } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java Mon May 13 17:11:31 2013 +0200 @@ -38,5 +38,6 @@ Unresolved, JavaSubroutineMismatch, ArithmeticException, - RuntimeConstraint + RuntimeConstraint, + LoopLimitCheck, } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Mon May 13 17:11:31 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.api.meta; import java.io.*; +import java.util.*; import com.oracle.graal.api.meta.ProfilingInfo.*; @@ -43,6 +44,8 @@ private static final long serialVersionUID = 7838575753661305744L; + public static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; + private final ResolvedJavaType type; private final double probability; @@ -78,6 +81,40 @@ } return 0; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(probability); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + type.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ProfiledType other = (ProfiledType) obj; + if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) { + return false; + } + return type.equals(other.type); + } + + @Override + public String toString() { + return "{" + type.getName() + ", " + probability + "}"; + } } private final TriState nullSeen; @@ -100,6 +137,7 @@ public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) { this.nullSeen = nullSeen; this.ptypes = ptypes; + assert notRecordedProbability != Double.NaN; this.notRecordedProbability = notRecordedProbability; assert isSorted(ptypes); } @@ -129,4 +167,154 @@ public ProfiledType[] getTypes() { return ptypes; } + + /** + * Searches for an entry of a given resolved Java type. + * + * @param type the type for which an entry should be searched + * @return the entry or null if no entry for this type can be found + */ + public ProfiledType findEntry(ResolvedJavaType type) { + if (ptypes != null) { + for (ProfiledType pt : ptypes) { + if (pt.getType() == type) { + return pt; + } + } + } + return null; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("JavaTypeProfile["); + builder.append(this.nullSeen); + builder.append(", "); + if (ptypes != null) { + for (ProfiledType pt : ptypes) { + builder.append(pt.toString()); + builder.append(", "); + } + } + builder.append(this.notRecordedProbability); + builder.append("]"); + return builder.toString(); + } + + public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { + if (otherProfile.getNotRecordedProbability() > 0.0) { + // Not useful for restricting since there is an unknown set of types occuring. + return this; + } + + if (this.getNotRecordedProbability() > 0.0) { + // We are unrestricted, so the other profile is always a better estimate. + return otherProfile; + } + + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getTypes().length; i++) { + ProfiledType ptype = getTypes()[i]; + ResolvedJavaType type = ptype.getType(); + if (otherProfile.isIncluded(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : this.nullSeen; + double newNotRecorded = this.notRecordedProbability; + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + public boolean isIncluded(ResolvedJavaType type) { + if (this.getNotRecordedProbability() > 0.0) { + return true; + } else { + for (int i = 0; i < getTypes().length; i++) { + ProfiledType ptype = getTypes()[i]; + ResolvedJavaType curType = ptype.getType(); + if (curType == type) { + return true; + } + } + } + return false; + } + + public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getTypes().length; i++) { + ProfiledType ptype = getTypes()[i]; + ResolvedJavaType type = ptype.getType(); + if (declaredType.isAssignableFrom(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (nonNull) ? TriState.FALSE : this.nullSeen; + double newNotRecorded = this.getNotRecordedProbability(); + // Assume for the types not recorded, the incompatibility rate is the same. + if (getTypes().length != 0) { + newNotRecorded *= ((double) result.size() / (double) getTypes().length); + } + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + private JavaTypeProfile createAdjustedProfile(ArrayList result, TriState newNullSeen, double newNotRecorded) { + if (result.size() != this.getTypes().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != this.nullSeen) { + if (result.size() == 0) { + return new JavaTypeProfile(newNullSeen, 1.0, ProfiledType.EMPTY_ARRAY); + } + double probabilitySum = 0.0; + for (int i = 0; i < result.size(); i++) { + probabilitySum += result.get(i).getProbability(); + } + probabilitySum += newNotRecorded; + + double factor = 1.0 / probabilitySum; // Normalize to 1.0 + assert factor > 1.0; + ProfiledType[] newResult = new ProfiledType[result.size()]; + for (int i = 0; i < newResult.length; ++i) { + ProfiledType curType = result.get(i); + newResult[i] = new ProfiledType(curType.getType(), Math.min(1.0, curType.getProbability() * factor)); + } + double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); + return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); + } + return this; + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (other instanceof JavaTypeProfile) { + JavaTypeProfile javaTypeProfile = (JavaTypeProfile) other; + if (javaTypeProfile.nullSeen != nullSeen) { + return false; + } + if (javaTypeProfile.notRecordedProbability != notRecordedProbability) { + return false; + } + if (javaTypeProfile.ptypes.length != ptypes.length) { + return false; + } + + for (int i = 0; i < ptypes.length; ++i) { + if (!ptypes[i].equals(javaTypeProfile.ptypes[i])) { + return false; + } + } + + return true; + } + return false; + } + + @Override + public int hashCode() { + return nullSeen.hashCode() + (int) Double.doubleToLongBits(notRecordedProbability) + ptypes.length * 13; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,7 @@ * {@link Kind#Int} for {@code int} and {@link Kind#Object} for all object types. A kind has a * single character short name, a Java name, and a set of flags further describing its behavior. */ -public enum Kind { +public enum Kind implements PlatformKind { /** The primitive boolean kind, represented as an int on the stack. */ Boolean('z', "boolean", true, java.lang.Boolean.TYPE, java.lang.Boolean.class), diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Mon May 13 17:11:31 2013 +0200 @@ -162,6 +162,13 @@ return (type == null) ? null : internalNameToJava(type.getName(), true, false); } + /** + * Returns the type name in the same format as {@link Class#getName()}. + */ + public static String toClassName(JavaType type) { + return internalNameToJava(type.getName(), true, true); + } + private static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { switch (name.charAt(0)) { case 'L': { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PlatformKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/PlatformKind.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.meta; + +/** + * Represents a platform-specific low-level type for values. + */ +public interface PlatformKind { + + String name(); +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Mon May 13 17:11:31 2013 +0200 @@ -24,7 +24,6 @@ import java.lang.annotation.*; import java.lang.reflect.*; -import java.lang.reflect.Method; import java.util.*; /** @@ -195,4 +194,18 @@ * @return The newly created and initialized object. */ Constant newInstance(Constant[] arguments); + + /** + * Gets the encoding of (that is, a constant representing the value of) this method. + * + * @return a constant representing a reference to this method + */ + Constant getEncoding(); + + /** + * Checks if this method is present in the virtual table. + * + * @return true is this method is present in the virtual table + */ + boolean isInVirtualMethodTable(); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Mon May 13 17:11:31 2013 +0200 @@ -41,14 +41,20 @@ }; private final Kind kind; + private final PlatformKind platformKind; /** * Initializes a new value of the specified kind. * - * @param kind the kind + * @param platformKind the kind */ - protected Value(Kind kind) { - this.kind = kind; + protected Value(PlatformKind platformKind) { + this.platformKind = platformKind; + if (platformKind instanceof Kind) { + this.kind = (Kind) platformKind; + } else { + this.kind = Kind.Illegal; + } } /** @@ -65,4 +71,29 @@ public final Kind getKind() { return kind; } + + /** + * Returns the platform specific kind used to store this value. + */ + public final PlatformKind getPlatformKind() { + return platformKind; + } + + @Override + public int hashCode() { + final int prime = 41; + int result = 1; + result = prime * result + kind.hashCode(); + result = prime * result + platformKind.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Value) { + Value other = (Value) obj; + return kind.equals(other.kind) && platformKind.equals(platformKind); + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon May 13 17:11:31 2013 +0200 @@ -380,7 +380,7 @@ } public final void addsd(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -389,7 +389,7 @@ } public final void addsd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -398,7 +398,7 @@ } public final void addss(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -407,7 +407,7 @@ } public final void addss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -513,6 +513,13 @@ emitOperandHelper(dst, src); } + public final void cmpl(AMD64Address dst, int imm32) { + prefix(dst); + emitByte(0x81); + emitOperandHelper(7, dst); + emitInt(imm32); + } + // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,. // The ZF is set if the compared values were equal, and cleared otherwise. @@ -540,7 +547,7 @@ } public final void cvtsd2ss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -549,8 +556,8 @@ } public final void cvtsd2ss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -559,7 +566,7 @@ } public final void cvtsi2sdl(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -568,7 +575,7 @@ } public final void cvtsi2sdl(Register dst, Register src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -577,7 +584,7 @@ } public final void cvtsi2ssl(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -586,7 +593,7 @@ } public final void cvtsi2ssl(Register dst, Register src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -595,7 +602,7 @@ } public final void cvtss2sd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -604,8 +611,8 @@ } public final void cvtss2sd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -622,7 +629,7 @@ } public final void cvttsd2sil(Register dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -639,7 +646,7 @@ } public final void cvttss2sil(Register dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -654,7 +661,7 @@ } public final void divsd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -663,8 +670,8 @@ } public final void divsd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -673,7 +680,7 @@ } public final void divss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -682,8 +689,8 @@ } public final void divss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -862,8 +869,8 @@ } public final void movapd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; int dstenc = dst.encoding; int srcenc = src.encoding; emitByte(0x66); @@ -887,8 +894,8 @@ } public final void movaps(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; int dstenc = dst.encoding; int srcenc = src.encoding; if (dstenc < 8) { @@ -918,22 +925,22 @@ } public final void movb(AMD64Address dst, Register src) { - assert src.isByte() : "must have byte register"; + assert src.getRegisterCategory() == AMD64.CPU : "must have byte register"; prefix(dst, src); // , true) emitByte(0x88); emitOperandHelper(src, dst); } public final void movdl(Register dst, Register src) { - if (dst.isFpu()) { - assert !src.isFpu() : "does this hold?"; + if (dst.getRegisterCategory() == AMD64.XMM) { + assert src.getRegisterCategory() != AMD64.XMM : "does this hold?"; emitByte(0x66); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x6E); emitByte(0xC0 | encode); - } else if (src.isFpu()) { - assert !dst.isFpu(); + } else if (src.getRegisterCategory() == AMD64.XMM) { + assert dst.getRegisterCategory() != AMD64.XMM; emitByte(0x66); // swap src/dst to get correct prefix int encode = prefixAndEncode(src.encoding, dst.encoding); @@ -981,7 +988,7 @@ * {@link AMD64MacroAssembler#movflt(Register, Register)}. */ public final void movlpd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0x66); prefix(src, dst); emitByte(0x0F); @@ -990,7 +997,7 @@ } public final void movq(Register dst, AMD64Address src) { - if (dst.isFpu()) { + if (dst.getRegisterCategory() == AMD64.XMM) { emitByte(0xF3); prefixq(src, dst); emitByte(0x0F); @@ -1010,7 +1017,7 @@ } public final void movq(AMD64Address dst, Register src) { - if (src.isFpu()) { + if (src.getRegisterCategory() == AMD64.XMM) { emitByte(0x66); prefixq(dst, src); emitByte(0x0F); @@ -1038,8 +1045,8 @@ } public final void movsd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -1048,7 +1055,7 @@ } public final void movsd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -1057,7 +1064,7 @@ } public final void movsd(AMD64Address dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(dst, src); emitByte(0x0F); @@ -1066,8 +1073,8 @@ } public final void movss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -1076,7 +1083,7 @@ } public final void movss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -1085,7 +1092,7 @@ } public final void movss(AMD64Address dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(dst, src); emitByte(0x0F); @@ -1137,7 +1144,7 @@ } public final void mulsd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); emitByte(0x0F); @@ -1146,8 +1153,8 @@ } public final void mulsd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); @@ -1157,7 +1164,7 @@ } public final void mulss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); @@ -1167,8 +1174,8 @@ } public final void mulss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -1512,8 +1519,8 @@ } public final void sqrtsd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; // HMM Table D-1 says sse2 // assert is64 || target.supportsSSE(); emitByte(0xF2); @@ -1545,8 +1552,8 @@ } public final void subsd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -1555,7 +1562,7 @@ } public final void subsd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefix(src, dst); @@ -1565,8 +1572,8 @@ } public final void subss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -1575,7 +1582,7 @@ } public final void subss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefix(src, dst); @@ -1611,20 +1618,20 @@ } public final void ucomisd(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0x66); ucomiss(dst, src); } public final void ucomisd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0x66); ucomiss(dst, src); } public final void ucomiss(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; prefix(src, dst); emitByte(0x0F); @@ -1633,8 +1640,8 @@ } public final void ucomiss(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; + assert src.getRegisterCategory() == AMD64.XMM; int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x2E); @@ -1668,7 +1675,7 @@ } public final void andps(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x54); @@ -1676,7 +1683,7 @@ } public final void andps(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; prefix(src, dst); emitByte(0x0F); emitByte(0x54); @@ -1694,7 +1701,7 @@ } public final void orps(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x56); @@ -1702,7 +1709,7 @@ } public final void orps(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; prefix(src, dst); emitByte(0x0F); emitByte(0x56); @@ -1720,7 +1727,7 @@ } public final void xorps(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x57); @@ -1728,7 +1735,7 @@ } public final void xorps(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; prefix(src, dst); emitByte(0x0F); emitByte(0x57); @@ -2014,7 +2021,7 @@ } public final void cvtsi2sdq(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); prefixq(src, dst); emitByte(0x0F); @@ -2023,7 +2030,7 @@ } public final void cvtsi2sdq(Register dst, Register src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -2032,7 +2039,7 @@ } public final void cvtsi2ssq(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); prefixq(src, dst); emitByte(0x0F); @@ -2041,7 +2048,7 @@ } public final void cvtsi2ssq(Register dst, Register src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -2058,7 +2065,7 @@ } public final void cvttsd2siq(Register dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF2); int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -2075,7 +2082,7 @@ } public final void cvttss2siq(Register dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; emitByte(0xF3); int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); @@ -2127,7 +2134,7 @@ if (isByte(value)) { emitByte(0x6B); emitByte(0xC0 | encode); - emitByte(value); + emitByte(value & 0xFF); } else { emitByte(0x69); emitByte(0xC0 | encode); @@ -2154,13 +2161,12 @@ // table D-1 says MMX/SSE2 emitByte(0x66); - if (dst.isFpu()) { - assert dst.isFpu(); + if (dst.getRegisterCategory() == AMD64.XMM) { int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0x6E); emitByte(0xC0 | encode); - } else if (src.isFpu()) { + } else if (src.getRegisterCategory() == AMD64.XMM) { // swap src/dst to get correct prefix int encode = prefixqAndEncode(src.encoding, dst.encoding); @@ -2414,11 +2420,16 @@ emitByte(b2 + i); } - public final void fld(AMD64Address src) { + public final void fld_d(AMD64Address src) { emitByte(0xDD); emitOperandHelper(0, src); } + public final void fld_s(AMD64Address src) { + emitByte(0xD9); + emitOperandHelper(0, src); + } + public final void fldln2() { emitByte(0xD9); emitByte(0xED); @@ -2434,11 +2445,49 @@ emitByte(0xF1); } - public final void fstp(AMD64Address src) { + public final void fstp_s(AMD64Address src) { + emitByte(0xD9); + emitOperandHelper(3, src); + } + + public final void fstp_d(AMD64Address src) { emitByte(0xDD); emitOperandHelper(3, src); } + private void emitFPUArith(int b1, int b2, int i) { + assert 0 <= i && i < 8 : "illegal FPU register: " + i; + emitByte(b1); + emitByte(b2 + i); + } + + public void ffree(int i) { + emitFPUArith(0xDD, 0xC0, i); + } + + public void fincstp() { + emitByte(0xD9); + emitByte(0xF7); + } + + public void fxch(int i) { + emitFPUArith(0xD9, 0xC8, i); + } + + public void fnstsw_ax() { + emitByte(0xDF); + emitByte(0xE0); + } + + public void fwait() { + emitByte(0x9B); + } + + public void fprem() { + emitByte(0xD9); + emitByte(0xF8); + } + public final void fsin() { emitByte(0xD9); emitByte(0xFE); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Mon May 13 17:11:31 2013 +0200 @@ -166,21 +166,12 @@ } } - public final void signExtendByte(Register reg) { - if (reg.isByte()) { - movsxb(reg, reg); - } else { - shll(reg, 24); - sarl(reg, 24); - } - } - public final void signExtendShort(Register reg) { movsxw(reg, reg); } public final void movflt(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; if (UseXmmRegToRegMoveAll) { movaps(dst, src); } else { @@ -189,17 +180,17 @@ } public final void movflt(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; movss(dst, src); } public final void movflt(AMD64Address dst, Register src) { - assert src.isFpu(); + assert src.getRegisterCategory() == AMD64.XMM; movss(dst, src); } public final void movdbl(Register dst, Register src) { - assert dst.isFpu() && src.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM && src.getRegisterCategory() == AMD64.XMM; if (UseXmmRegToRegMoveAll) { movapd(dst, src); } else { @@ -208,7 +199,7 @@ } public final void movdbl(Register dst, AMD64Address src) { - assert dst.isFpu(); + assert dst.getRegisterCategory() == AMD64.XMM; if (UseXmmLoadAndClearUpper) { movsd(dst, src); } else { @@ -227,17 +218,12 @@ } public final void flog(Register dest, Register value, boolean base10) { - assert dest.isFpu() && value.isFpu(); - - AMD64Address tmp = new AMD64Address(AMD64.rsp); if (base10) { fldlg2(); } else { fldln2(); } - subq(AMD64.rsp, 8); - movsd(tmp, value); - fld(tmp); + AMD64Address tmp = trigPrologue(value); fyl2x(); trigEpilogue(dest, tmp); } @@ -261,18 +247,23 @@ trigEpilogue(dest, tmp); } + public final void fpop() { + ffree(0); + fincstp(); + } + private AMD64Address trigPrologue(Register value) { - assert value.isFpu(); + assert value.getRegisterCategory() == AMD64.XMM; AMD64Address tmp = new AMD64Address(AMD64.rsp); subq(AMD64.rsp, 8); movsd(tmp, value); - fld(tmp); + fld_d(tmp); return tmp; } private void trigEpilogue(Register dest, AMD64Address tmp) { - assert dest.isFpu(); - fstp(tmp); + assert dest.getRegisterCategory() == AMD64.XMM; + fstp_d(tmp); movsd(dest, tmp); addq(AMD64.rsp, 8); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Mon May 13 17:11:31 2013 +0200 @@ -59,7 +59,7 @@ DisassemblerProvider dis = Graal.getRuntime().getCapability(DisassemblerProvider.class); if (dis != null) { String disasm = dis.disassemble(code); - Assert.assertTrue(String.valueOf(code.getMethod()), disasm == null || disasm.length() > 0); + Assert.assertTrue(code.toString(), disasm == null || disasm.length() > 0); } return code; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Address.Scale; @@ -48,6 +47,7 @@ import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack; import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst; import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp; @@ -78,25 +78,22 @@ */ public abstract class AMD64LIRGenerator extends LIRGenerator { - public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class); - public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class); - private static final RegisterValue RAX_I = AMD64.rax.asValue(Kind.Int); private static final RegisterValue RAX_L = AMD64.rax.asValue(Kind.Long); private static final RegisterValue RDX_I = AMD64.rdx.asValue(Kind.Int); private static final RegisterValue RDX_L = AMD64.rdx.asValue(Kind.Long); private static final RegisterValue RCX_I = AMD64.rcx.asValue(Kind.Int); - public static class AMD64SpillMoveFactory implements LIR.SpillMoveFactory { + private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory { @Override public LIRInstruction createMove(AllocatableValue result, Value input) { - return AMD64LIRGenerator.createMove(result, input); + return AMD64LIRGenerator.this.createMove(result, input); } } - public AMD64LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - super(graph, runtime, target, frameMap, method, lir); + public AMD64LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { + super(graph, runtime, target, frameMap, cc, lir); lir.spillMoveFactory = new AMD64SpillMoveFactory(); } @@ -143,7 +140,7 @@ return result; } - private static AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { + protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { if (src instanceof AMD64AddressValue) { return new LeaOp(dst, (AMD64AddressValue) src); } else if (isRegister(src) || isStackSlot(dst)) { @@ -177,7 +174,7 @@ AllocatableValue indexRegister; Scale scaleEnum; - if (index != Value.ILLEGAL && scale != 0) { + if (!index.equals(Value.ILLEGAL) && scale != 0) { scaleEnum = Scale.fromInt(scale); if (isConstant(index)) { finalDisp += asConstant(index).asLong() * scale; @@ -196,7 +193,7 @@ } else { displacementInt = 0; AllocatableValue displacementRegister = load(Constant.forLong(finalDisp)); - if (baseRegister == Value.ILLEGAL) { + if (baseRegister.equals(Value.ILLEGAL)) { baseRegister = displacementRegister; } else if (indexRegister == Value.ILLEGAL) { indexRegister = displacementRegister; @@ -525,7 +522,7 @@ } private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) { - AllocatableValue rax = AMD64.rax.asValue(a.getKind()); + AllocatableValue rax = AMD64.rax.asValue(a.getPlatformKind()); emitMove(rax, a); append(new DivRemOp(op, rax, asAllocatable(b), state)); } @@ -554,12 +551,12 @@ emitDivRem(LDIV, a, b, state(deopting)); return emitMove(RAX_L); case Float: { - Variable result = newVariable(a.getKind()); + Variable result = newVariable(a.getPlatformKind()); append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b))); return result; } case Double: { - Variable result = newVariable(a.getKind()); + Variable result = newVariable(a.getPlatformKind()); append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b))); return result; } @@ -578,12 +575,14 @@ emitDivRem(LREM, a, b, state(deopting)); return emitMove(RDX_L); case Float: { - RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM); - return emitCall(stub, stub.getCallingConvention(), null, a, b); + Variable result = newVariable(a.getPlatformKind()); + append(new FPDivRemOp(FREM, result, load(a), load(b))); + return result; } case Double: { - RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM); - return emitCall(stub, stub.getCallingConvention(), null, a, b); + Variable result = newVariable(a.getPlatformKind()); + append(new FPDivRemOp(DREM, result, load(a), load(b))); + return result; } default: throw GraalInternalError.shouldNotReachHere(); @@ -657,7 +656,7 @@ } private Variable emitShift(AMD64Arithmetic op, Value a, Value b) { - Variable result = newVariable(a.getKind()); + Variable result = newVariable(a.getPlatformKind()); AllocatableValue input = asAllocatable(a); if (isConstant(b)) { append(new BinaryRegConst(op, result, input, asConstant(b))); @@ -920,8 +919,7 @@ sig[i] = node.arguments.get(i).stamp().javaType(runtime); } - CallingConvention cc = frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false); - Value[] parameters = visitInvokeArguments(cc, node.arguments); + Value[] parameters = visitInvokeArguments(frameMap.registerConfig.getCallingConvention(CallingConvention.Type.JavaCall, null, sig, target(), false), node.arguments); append(new AMD64BreakpointOp(parameters)); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Mon May 13 17:11:31 2013 +0200 @@ -24,6 +24,7 @@ import java.lang.reflect.Method; +import org.junit.Ignore; import org.junit.Test; /** @@ -36,7 +37,12 @@ compile("testAddConst1I"); } - public static int testAddConst1I(int a) { + @Ignore + public void testAddInvoke() { + invoke(compile("testAddConst1I"), new Integer(42)); + } + + public int testAddConst1I(int a) { return a + 1; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java Mon May 13 17:11:31 2013 +0200 @@ -22,35 +22,60 @@ */ package com.oracle.graal.compiler.ptx.test; +import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.ptx.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; +import com.oracle.graal.api.code.CallingConvention.*; +import com.oracle.graal.api.runtime.Graal; +import com.oracle.graal.compiler.GraalCompiler; +import com.oracle.graal.compiler.ptx.PTXBackend; +import com.oracle.graal.compiler.test.GraalCompilerTest; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.java.GraphBuilderConfiguration; +import com.oracle.graal.java.GraphBuilderPhase; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.spi.GraalCodeCacheProvider; +import com.oracle.graal.phases.OptimisticOptimizations; +import com.oracle.graal.phases.PhasePlan; import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.ptx.*; +import com.oracle.graal.ptx.PTX; public abstract class PTXTestBase extends GraalCompilerTest { + private StructuredGraph sg; + protected CompilationResult compile(String test) { StructuredGraph graph = parse(test); + sg = graph; Debug.dump(graph, "Graph"); TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true); - PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target); + PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(GraalCodeCacheProvider.class), target); PhasePlan phasePlan = new PhasePlan(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase()); new PTXPhase().apply(graph); - CompilationResult result = GraalCompiler.compileMethod(runtime, graalRuntime().getReplacements(), ptxBackend, target, graph.method(), graph, null, phasePlan, OptimisticOptimizations.NONE, + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + CompilationResult result = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, graalRuntime().getReplacements(), ptxBackend, target, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog()); return result; } + protected StructuredGraph getStructuredGraph() { + return sg; + } + + @SuppressWarnings("unused") + protected void invoke(CompilationResult result, Object... args) { + try { + // not quite yet - need multi-architecture Method changes from JDK-8013168 + // Object[] executeArgs = argsWithReceiver(this, args); + // InstalledCode installedCode = + // runtime.addMethod(getStructuredGraph().method(), result); + // installedCode.executeVarargs(executeArgs); + } catch (Throwable th) { + th.printStackTrace(); + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Mon May 13 17:11:31 2013 +0200 @@ -42,17 +42,14 @@ } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - return new PTXLIRGenerator(graph, runtime(), target, frameMap, method, lir); + public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) { + return new PTXLIRGenerator(graph, runtime(), target, frameMap, cc, lir); } class HotSpotFrameContext implements FrameContext { @Override public void enter(TargetMethodAssembler tasm) { - Buffer codeBuffer = tasm.asm.codeBuffer; - codeBuffer.emitString(".version 1.4"); - codeBuffer.emitString(".target sm_10"); // codeBuffer.emitString(".address_size 32"); // PTX ISA version 2.3 } @@ -62,6 +59,11 @@ } @Override + protected AbstractAssembler createAssembler(FrameMap frameMap) { + return new PTXAssembler(target, frameMap.registerConfig); + } + + @Override public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { // Omit the frame if the method: // - has no spill slots or other slots allocated during register allocation @@ -69,22 +71,25 @@ // - has no incoming arguments passed on the stack // - has no instructions with debug info FrameMap frameMap = lirGen.frameMap; - AbstractAssembler masm = new PTXAssembler(target, frameMap.registerConfig); + AbstractAssembler masm = createAssembler(frameMap); HotSpotFrameContext frameContext = new HotSpotFrameContext(); - TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); + TargetMethodAssembler tasm = new PTXTargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); tasm.setFrameSize(frameMap.frameSize()); return tasm; } @Override - public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { + public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) { // Emit the prologue - final String name = method.getName(); + assert codeCacheOwner != null : lirGen.getGraph() + " is not associated with a method"; + final String name = codeCacheOwner.getName(); Buffer codeBuffer = tasm.asm.codeBuffer; + codeBuffer.emitString(".version 1.4"); + codeBuffer.emitString(".target sm_10"); codeBuffer.emitString0(".entry " + name + " ("); codeBuffer.emitString(""); - Signature signature = method.getSignature(); + Signature signature = codeCacheOwner.getSignature(); for (int i = 0; i < signature.getParameterCount(false); i++) { String param = ".param .u32 param" + i; codeBuffer.emitString(param); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -28,11 +28,7 @@ import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.ptx.PTXCompare.*; -import com.oracle.graal.api.code.CodeCacheProvider; -import com.oracle.graal.api.code.DeoptimizationAction; -import com.oracle.graal.api.code.RuntimeCallTarget; -import com.oracle.graal.api.code.StackSlot; -import com.oracle.graal.api.code.TargetDescription; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.NumUtil; @@ -85,8 +81,8 @@ } } - public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - super(graph, runtime, target, frameMap, method, lir); + public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { + super(graph, runtime, target, frameMap, cc, lir); lir.spillMoveFactory = new PTXSpillMoveFactory(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,61 @@ +/* + * 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.compiler.ptx; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; + +public class PTXTargetMethodAssembler extends TargetMethodAssembler { + + private static CompilerToGPU toGPU = HotSpotGraalRuntime.graalRuntime().getCompilerToGPU(); + private static boolean validDevice = toGPU.deviceInit(); + + // detach ?? + + public PTXTargetMethodAssembler(TargetDescription target, CodeCacheProvider runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, CompilationResult compilationResult) { + super(target, runtime, frameMap, asm, frameContext, compilationResult); + } + + @Override + public CompilationResult finishTargetMethod(StructuredGraph graph) { + ResolvedJavaMethod method = graph.method(); + assert method != null : graph + " is not associated wth a method"; + CompilationResult graalCompile = super.finishTargetMethod(graph); + + try { + if (validDevice) { + toGPU.generateKernel(graalCompile.getTargetCode(), method.getName()); + } + } catch (Throwable th) { + th.printStackTrace(); + } + + return graalCompile; // for now + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -38,8 +38,8 @@ */ public class SPARCLIRGenerator extends LIRGenerator { - public SPARCLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - super(graph, runtime, target, frameMap, method, lir); + public SPARCLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { + super(graph, runtime, target, frameMap, cc, lir); // SPARC: Implement lir generator. } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon May 13 17:11:31 2013 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** @@ -334,10 +333,6 @@ new CanonicalizerPhase().apply(graph, context); new PartialEscapeAnalysisPhase(false, false).apply(graph, context); - for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { - materialize.getVirtualObject().materializeAt(materialize, materialize.getValues(), false, materialize.getLockCount()); - } - new CullFrameStatesPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); new CanonicalizerPhase().apply(graph, context); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java Mon May 13 17:11:31 2013 +0200 @@ -26,8 +26,9 @@ import junit.framework.Assert; -import org.junit.*; +import org.junit.Test; +import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -61,7 +62,49 @@ @Test public void test2() { - compileSnippet("test2Snippet", 5, 2); + compileSnippet("test2Snippet", 5, 1); + } + + public static long test3Snippet(A1 a1) { + long result = a1.x1; + A2 a2 = (A2) a1; + if (a1.x1 == 42) { + A3 a3 = (A3) a2; + result = a3.x3; + } + return result; + } + + @Test + public void test3() { + compileSnippet("test3Snippet", 2, 2); + } + + public static long test4Snippet(A1 a1, A1 b1) { + A2 a2 = (A2) a1; + A3 b3 = (A3) b1; + return a2.x2 + b3.x3; + } + + @Test + public void test4() { + compileSnippet("test4Snippet", 2, 2); + } + + public static long test5Snippet(A1 a1) { + long sum = 0; + A2 a2 = (A2) a1; + A3 a3 = (A3) a2; + sum += a2.x2; + return sum + a3.x3; + } + + @Test + public void test5() { + StructuredGraph graph = compileSnippet("test5Snippet", 2, 1); + for (LoadFieldNode lfn : graph.getNodes().filter(LoadFieldNode.class)) { + Assert.assertTrue(lfn.object() instanceof CheckCastNode); + } } private StructuredGraph compileSnippet(final String snippet, final int checkcasts, final int afterCanon) { @@ -70,8 +113,9 @@ @Override public StructuredGraph call() throws Exception { StructuredGraph graph = parse(snippet); + Debug.dump(graph, "After parsing: " + snippet); Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count()); - new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); Assert.assertEquals(afterCanon, graph.getNodes(CheckCastNode.class).count()); return graph; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.compiler.test; +import static com.oracle.graal.api.code.CodeUtil.*; + import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -29,6 +31,7 @@ import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.*; @@ -410,7 +413,8 @@ phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase()); editPhasePlan(method, graph, phasePlan); - CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL, + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, backend, runtime().getTarget(), null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog()); if (printCompilation) { TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.compiler.test; +import static com.oracle.graal.api.code.CodeUtil.*; import static org.junit.Assert.*; import java.lang.reflect.*; @@ -29,6 +30,7 @@ import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.code.CompilationResult.Call; import com.oracle.graal.api.code.CompilationResult.Infopoint; import com.oracle.graal.compiler.*; @@ -56,7 +58,8 @@ public void callInfopoints() { final Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); - final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(), + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + final CompilationResult cr = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, new SpeculationLog()); for (Infopoint sp : cr.getInfopoints()) { assertNotNull(sp.reason); @@ -77,7 +80,8 @@ } } assertTrue(graphLineSPs > 0); - final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(true), + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + final CompilationResult cr = GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, getDefaultPhasePlan(true), OptimisticOptimizations.ALL, new SpeculationLog()); int lineSPs = 0; for (Infopoint sp : cr.getInfopoints()) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Mon May 13 17:11:31 2013 +0200 @@ -146,7 +146,7 @@ @Test public void testLoop1() { SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); - assertEquals(7, schedule.getCFG().getBlocks().length); + assertEquals(6, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, true); } @@ -170,7 +170,7 @@ @Test public void testLoop2() { SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); - assertEquals(7, schedule.getCFG().getBlocks().length); + assertEquals(6, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); } @@ -185,7 +185,7 @@ @Test public void testArrayCopy() { SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); - StructuredGraph graph = (StructuredGraph) schedule.getCFG().getStartBlock().getBeginNode().graph(); + StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); ReturnNode ret = graph.getNodes(ReturnNode.class).first(); assertTrue(ret.result() instanceof FloatingReadNode); assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); @@ -219,11 +219,12 @@ @Override public SchedulePhase call() throws Exception { StructuredGraph graph = parse(snippet); + Assumptions assumptions = new Assumptions(false); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { - Assumptions assumptions = new Assumptions(false); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); } - HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { for (Node node : graph.getNodes()) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Mon May 13 17:11:31 2013 +0200 @@ -32,7 +32,8 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.Lowerable.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; @@ -65,17 +66,24 @@ public void run() { StructuredGraph graph = compileTestSnippet(snippet); + int counter = 0; for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) { - Object locId = rn.location().locationIdentity(); - if (locId instanceof ResolvedJavaField) { - ResolvedJavaField field = (ResolvedJavaField) locId; - if (field.getName().equals("x")) { - Assert.assertTrue(rn.object() instanceof LocalNode); - } else { - Assert.assertTrue(rn.object() instanceof UnsafeCastNode); + if (rn.location() instanceof ConstantLocationNode && rn.object().stamp() instanceof ObjectStamp) { + long disp = ((ConstantLocationNode) rn.location()).getDisplacement(); + ResolvedJavaType receiverType = rn.object().objectStamp().type(); + ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(disp); + + if (field != null) { + if (field.getName().equals("x")) { + Assert.assertTrue(rn.object() instanceof LocalNode); + } else { + Assert.assertTrue(rn.object() instanceof UnsafeCastNode); + } + counter++; } } } + Assert.assertEquals(2, counter); Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,15 +22,11 @@ */ package com.oracle.graal.compiler.test; -import java.util.*; - import org.junit.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.phases.common.*; @@ -96,36 +92,10 @@ Debug.dump(graph, "After lowering"); - ArrayList merges = new ArrayList<>(); - ArrayList reads = new ArrayList<>(); - for (Node n : graph.getNodes()) { - if (n instanceof MergeNode) { - // check shape - MergeNode merge = (MergeNode) n; - - if (merge.inputs().count() == 2) { - for (EndNode m : merge.forwardEnds()) { - if (m.predecessor() != null && m.predecessor() instanceof BeginNode && m.predecessor().predecessor() instanceof IfNode) { - IfNode o = (IfNode) m.predecessor().predecessor(); - if (o.falseSuccessor().next() instanceof DeoptimizeNode) { - merges.add(merge); - } - } - } - } - } - if (n instanceof IntegerAddNode) { - IntegerAddNode ian = (IntegerAddNode) n; - - Assert.assertTrue(ian.y() instanceof ConstantNode); - Assert.assertTrue(ian.x() instanceof FloatingReadNode); - reads.add((FloatingReadNode) ian.x()); - } - } - - Assert.assertTrue(merges.size() >= reads.size()); - for (int i = 0; i < reads.size(); i++) { - assertOrderedAfterSchedule(graph, merges.get(i), reads.get(i)); + for (FloatingReadNode node : graph.getNodes(LocalNode.class).first().usages().filter(FloatingReadNode.class)) { + // Checking that the parameter a is not directly used for the access to field + // x10 (because x10 must be guarded by the checkcast). + Assert.assertTrue(node.location().getLocationIdentity() == LocationNode.FINAL_LOCATION); } } }); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,25 +22,34 @@ */ package com.oracle.graal.compiler.test; -import static org.junit.Assert.*; - import org.junit.*; +import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; -public class SimpleCFGTest { +public class SimpleCFGTest extends GraalCompilerTest { + + private static void dumpGraph(final StructuredGraph graph) { + Debug.scope("SimpleCFGTest", new Runnable() { + + @Override + public void run() { + Debug.dump(graph, "Graph"); + } + }); + } @Test public void testImplies() { StructuredGraph graph = new StructuredGraph(); - EndNode trueEnd = graph.add(new EndNode()); - EndNode falseEnd = graph.add(new EndNode()); + AbstractEndNode trueEnd = graph.add(new EndNode()); + AbstractEndNode falseEnd = graph.add(new EndNode()); - BeginNode trueBegin = graph.add(new BeginNode()); + AbstractBeginNode trueBegin = graph.add(new BeginNode()); trueBegin.setNext(trueEnd); - BeginNode falseBegin = graph.add(new BeginNode()); + AbstractBeginNode falseBegin = graph.add(new BeginNode()); falseBegin.setNext(falseEnd); IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5)); @@ -52,6 +61,8 @@ ReturnNode returnNode = graph.add(new ReturnNode(null)); merge.setNext(returnNode); + dumpGraph(graph); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); Block[] blocks = cfg.getBlocks(); @@ -88,15 +99,15 @@ } public static void assertDominator(Block block, Block expectedDominator) { - assertEquals("dominator of " + block, expectedDominator, block.getDominator()); + Assert.assertEquals("dominator of " + block, expectedDominator, block.getDominator()); } public static void assertDominatedSize(Block block, int size) { - assertEquals("number of dominated blocks of " + block, size, block.getDominated().size()); + Assert.assertEquals("number of dominated blocks of " + block, size, block.getDominated().size()); } public static void assertPostdominator(Block block, Block expectedPostdominator) { - assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator()); + Assert.assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator()); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,713 @@ +/* + * 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.compiler.test; + +import java.util.*; +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; +import com.oracle.graal.phases.tiers.*; + +/** + * The following tests validate the write barrier verification phase. For every tested snippet, an + * array of write barrier indices and the total write barrier number are passed as parameters. The + * indices denote the barriers that will be manually removed. The write barrier verification phase + * runs after the write barrier removal and depending on the result an assertion might be generated. + * The tests anticipate the presence or not of an assertion generated by the verification phase. + */ +public class WriteBarrierVerificationTest extends GraalCompilerTest { + + public static int barrierIndex; + + public static class Container { + + public Container a; + public Container b; + } + + private static native void safepoint(); + + public static void test1Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + safepoint(); + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test1() { + test("test1Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test2() { + test("test1Snippet", 2, new int[]{2}); + } + + public static void test2Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test3() { + test("test2Snippet", 2, new int[]{1}); + } + + @Test + public void test4() { + test("test2Snippet", 2, new int[]{2}); + } + + public static void test3Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + } + + @Test(expected = AssertionError.class) + public void test5() { + test("test3Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test6() { + test("test3Snippet", 4, new int[]{3, 4}); + } + + @Test(expected = AssertionError.class) + public void test7() { + test("test3Snippet", 4, new int[]{1}); + } + + @Test + public void test8() { + test("test3Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test9() { + test("test3Snippet", 4, new int[]{3}); + } + + @Test + public void test10() { + test("test3Snippet", 4, new int[]{4}); + } + + public static void test4Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + } + } + + @Test(expected = AssertionError.class) + public void test11() { + test("test4Snippet", 5, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test12() { + test("test4Snippet", 5, new int[]{4, 5}); + } + + @Test(expected = AssertionError.class) + public void test13() { + test("test4Snippet", 5, new int[]{1}); + } + + public static void test5Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (main.a == main.b) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test14() { + test("test5Snippet", 5, new int[]{1}); + } + + @Test + public void test15() { + test("test5Snippet", 5, new int[]{2}); + } + + @Test + public void test16() { + test("test5Snippet", 5, new int[]{4}); + } + + @Test + public void test17() { + test("test5Snippet", 5, new int[]{3}); + } + + @Test + public void test18() { + test("test5Snippet", 5, new int[]{5}); + } + + @Test + public void test19() { + test("test5Snippet", 5, new int[]{2, 3}); + } + + @Test + public void test20() { + test("test5Snippet", 5, new int[]{4, 5}); + } + + public static void test6Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp1.a.a; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp2.a.a; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test21() { + test("test6Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test22() { + test("test6Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test23() { + test("test6Snippet", 5, new int[]{3}); + } + + @Test + public void test24() { + test("test6Snippet", 5, new int[]{4}); + } + + public static void test7Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + } + barrierIndex = 3; + main.b = temp2; + safepoint(); + } + + @Test + public void test25() { + test("test7Snippet", 3, new int[]{2}); + } + + @Test + public void test26() { + test("test7Snippet", 3, new int[]{3}); + } + + @Test + public void test27() { + test("test7Snippet", 3, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test28() { + test("test7Snippet", 3, new int[]{1}); + } + + public static void test8Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main.a = temp1; + } + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test29() { + test("test8Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test30() { + test("test8Snippet", 2, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test31() { + test("test8Snippet", 2, new int[]{1, 2}); + } + + public static void test9Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + } else { + barrierIndex = 2; + main2.a = temp1; + } + barrierIndex = 3; + main1.b = temp2; + barrierIndex = 4; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test32() { + test("test9Snippet", 4, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test33() { + test("test9Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test34() { + test("test9Snippet", 4, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test35() { + test("test9Snippet", 4, new int[]{4}); + } + + @Test(expected = AssertionError.class) + public void test36() { + test("test9Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test37() { + test("test9Snippet", 4, new int[]{3, 4}); + } + + public static void test10Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main2.a = temp2; + } else { + barrierIndex = 3; + main2.a = temp1; + } + barrierIndex = 4; + main1.b = temp2; + barrierIndex = 5; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test38() { + test("test10Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test39() { + test("test10Snippet", 5, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test40() { + test("test10Snippet", 5, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test41() { + test("test10Snippet", 5, new int[]{4}); + } + + @Test + public void test42() { + test("test10Snippet", 5, new int[]{5}); + } + + @Test(expected = AssertionError.class) + public void test43() { + test("test10Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test44() { + test("test10Snippet", 5, new int[]{1, 2, 3}); + } + + @Test(expected = AssertionError.class) + public void test45() { + test("test10Snippet", 5, new int[]{3, 4}); + } + + public static void test11Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container main3 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main3.a = temp1; + if (!test) { + barrierIndex = 3; + main2.a = temp2; + } else { + barrierIndex = 4; + main1.a = temp2; + barrierIndex = 5; + main3.a = temp2; + } + } else { + barrierIndex = 6; + main1.b = temp2; + for (int i = 0; i < 10; i++) { + barrierIndex = 7; + main3.a = temp1; + } + barrierIndex = 8; + main3.b = temp2; + } + barrierIndex = 9; + main1.b = temp2; + barrierIndex = 10; + main2.b = temp2; + barrierIndex = 11; + main3.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test46() { + test("test11Snippet", 11, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test47() { + test("test11Snippet", 11, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test48() { + test("test11Snippet", 11, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test49() { + test("test11Snippet", 11, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test50() { + test("test11Snippet", 11, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test51() { + test("test11Snippet", 11, new int[]{8}); + } + + @Test(expected = AssertionError.class) + public void test52() { + test("test11Snippet", 11, new int[]{9}); + } + + @Test(expected = AssertionError.class) + public void test53() { + test("test11Snippet", 11, new int[]{10}); + } + + @Test + public void test54() { + test("test11Snippet", 11, new int[]{4}); + } + + @Test + public void test55() { + test("test11Snippet", 11, new int[]{5}); + } + + @Test + public void test56() { + test("test11Snippet", 11, new int[]{11}); + } + + public static void test12Snippet(boolean test) { + Container main = new Container(); + Container main1 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 7; + main1.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + barrierIndex = 5; + main.a = temp1; + barrierIndex = 6; + main.b = temp1; + barrierIndex = 8; + main1.b = temp1; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test57() { + test("test12Snippet", 8, new int[]{5}); + } + + @Test + public void test58() { + test("test12Snippet", 8, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test59() { + test("test12Snippet", 8, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test60() { + test("test12Snippet", 8, new int[]{8}); + } + + private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) { + + AssertionError expectedError = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Callable() { + + public AssertionError call() { + final StructuredGraph graph = parse(snippet); + HighTierContext highTierContext = new HighTierContext(runtime(), new Assumptions(false), replacements); + MidTierContext midTierContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL); + + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highTierContext); + new GuardLoweringPhase().apply(graph, midTierContext); + new SafepointInsertionPhase().apply(graph); + new WriteBarrierAdditionPhase().apply(graph); + + // First, the total number of expected barriers is checked. + final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers == barriers); + + // Iterate over all write nodes and remove barriers according to input indices. + NodeIteratorClosure closure = new NodeIteratorClosure() { + + @Override + protected Boolean processNode(FixedNode node, Boolean currentState) { + if (node instanceof WriteNode) { + WriteNode write = (WriteNode) node; + LocationIdentity obj = write.getLocationIdentities()[0]; + if (obj instanceof ResolvedJavaField) { + if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) { + /* + * A "barrierIndex" variable was found and is checked against + * the input barrier array. + */ + if (eliminateBarrier(write.value().asConstant().asInt(), removedBarrierIndices)) { + return true; + } + } + } + } else if (node instanceof SerialWriteBarrier) { + // Remove flagged write barriers. + if (currentState) { + graph.removeFixed(((SerialWriteBarrier) node)); + return false; + } + } + return currentState; + } + + private boolean eliminateBarrier(int index, int[] map) { + for (int i = 0; i < map.length; i++) { + if (map[i] == index) { + return true; + } + } + return false; + } + + @Override + protected Map processLoop(LoopBeginNode loop, Boolean initialState) { + return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; + } + + @Override + protected Boolean merge(MergeNode merge, List states) { + return false; + } + + @Override + protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { + return false; + } + }; + + DebugConfig config = DebugScope.getConfig(); + try { + ReentrantNodeIterator.apply(closure, graph.start(), false, null); + Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.output())); + new WriteBarrierVerificationPhase().apply(graph); + } catch (AssertionError error) { + /* + * Catch assertion, test for expected one and re-throw in order to validate unit + * test. + */ + Assert.assertTrue(error.getMessage().equals("Write barrier must be present")); + return error; + } finally { + Debug.setConfig(config); + } + return null; + } + }); + if (expectedError != null) { + throw expectedError; + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,12 +22,15 @@ */ package com.oracle.graal.compiler.test.backend; +import static com.oracle.graal.api.code.CodeUtil.*; + import java.util.*; import java.util.concurrent.*; import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.test.*; @@ -97,7 +100,7 @@ Value def = move.getResult(); Value use = move.getInput(); if (ValueUtil.isRegister(def)) { - if (ValueUtil.isRegister(use) && ValueUtil.asRegister(def) != ValueUtil.asRegister(use)) { + if (ValueUtil.isRegister(use)) { regRegMoves++; } } else if (ValueUtil.isStackSlot(def)) { @@ -123,7 +126,8 @@ @Override public RegisterStats call() { - GraalCompiler.emitLIR(backend, backend.target, lir, graph, graph.method()); + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + GraalCompiler.emitLIR(backend, backend.target, lir, graph, cc); return new RegisterStats(lir); } }); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Mon May 13 17:11:31 2013 +0200 @@ -35,16 +35,15 @@ import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** - * In these test cases the probability of all invokes is set to a high value, such that an - * InliningPhase should inline them all. After that, the EscapeAnalysisPhase is expected to remove - * all allocations and return the correct values. + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. */ public class EscapeAnalysisTest extends GraalCompilerTest { @@ -230,7 +229,7 @@ Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); } - int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count(); + int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(CommitAllocationNode.class).count(); Assert.assertEquals(0, newInstanceCount); return returnNode; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon May 13 17:11:31 2013 +0200 @@ -35,17 +35,16 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; /** - * In these test cases the probability of all invokes is set to a high value, such that an - * InliningPhase should inline them all. After that, the PartialEscapeAnalysisPhase is expected to - * remove all allocations and return the correct values. + * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct + * values. */ public class PartialEscapeAnalysisTest extends GraalCompilerTest { @@ -137,9 +136,9 @@ NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply(); double probabilitySum = 0; int materializeCount = 0; - for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) { - probabilitySum += nodeProbabilities.get(materialize); - materializeCount++; + for (CommitAllocationNode materialize : result.getNodes(CommitAllocationNode.class)) { + probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size(); + materializeCount += materialize.getVirtualObjects().size(); } Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.compiler; -import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; @@ -45,17 +44,29 @@ import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.verify.*; import com.oracle.graal.virtual.phases.ea.*; +/** + * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}. + */ public class GraalCompiler { - public static CompilationResult compileMethod(final GraalCodeCacheProvider runtime, final Replacements replacements, final Backend backend, final TargetDescription target, - final ResolvedJavaMethod method, final StructuredGraph graph, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts, + /** + * Requests compilation of a given graph. + * + * @param graph the graph to be compiled + * @param cc the calling convention for calls to the code compiled for {@code graph} + * @param installedCodeOwner the method the compiled code will be + * {@linkplain InstalledCode#getMethod() associated} with once installed. This + * argument can be null. + * @return the result of the compilation + */ + public static CompilationResult compileGraph(final StructuredGraph graph, final CallingConvention cc, final ResolvedJavaMethod installedCodeOwner, final GraalCodeCacheProvider runtime, + final Replacements replacements, final Backend backend, final TargetDescription target, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { - assert (method.getModifiers() & Modifier.NATIVE) == 0 : "compiling native methods is not supported"; - final CompilationResult compilationResult = new CompilationResult(); - Debug.scope("GraalCompiler", new Object[]{graph, method, runtime}, new Runnable() { + Debug.scope("GraalCompiler", new Object[]{graph, runtime}, new Runnable() { public void run() { final Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions); @@ -68,13 +79,13 @@ final LIRGenerator lirGen = Debug.scope("BackEnd", lir, new Callable() { public LIRGenerator call() { - return emitLIR(backend, target, lir, graph, method); + return emitLIR(backend, target, lir, graph, cc); } }); Debug.scope("CodeGen", lirGen, new Runnable() { public void run() { - emitCode(backend, getLeafGraphIdArray(graph), assumptions, method, lirGen, compilationResult); + emitCode(backend, getLeafGraphIdArray(graph), assumptions, lirGen, compilationResult, installedCodeOwner); } }); @@ -114,6 +125,7 @@ } else { Debug.dump(graph, "initial state"); } + new VerifyValueUsage(runtime).apply(graph); if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); @@ -135,12 +147,13 @@ } InliningPhase.storeHighLevelStatistics(graph); } + TypeProfileProxyNode.cleanFromGraph(graph); plan.runPhases(PhasePosition.HIGH_LEVEL, graph); Suites.DEFAULT.getHighTier().apply(graph, highTierContext); InliningPhase.storeMidLevelStatistics(graph); - MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements, target); + MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements, target, optimisticOpts); Suites.DEFAULT.getMidTier().apply(graph, midTierContext); plan.runPhases(PhasePosition.LOW_LEVEL, graph); @@ -175,9 +188,9 @@ } - public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) { + public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, CallingConvention cc) { final FrameMap frameMap = backend.newFrameMap(); - final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, method, lir); + final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, cc, lir); Debug.scope("LIRGen", lirGen, new Runnable() { @@ -206,16 +219,16 @@ Debug.scope("Allocator", new Runnable() { public void run() { - new LinearScan(target, method, lir, lirGen, frameMap).allocate(); + new LinearScan(target, lir, lirGen, frameMap).allocate(); } }); return lirGen; } - public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, ResolvedJavaMethod method, LIRGenerator lirGen, CompilationResult compilationResult) { + public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, LIRGenerator lirGen, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner) { TargetMethodAssembler tasm = backend.newAssembler(lirGen, compilationResult); - backend.emitCode(tasm, method, lirGen); - CompilationResult result = tasm.finishTargetMethod(method, false); + backend.emitCode(tasm, lirGen, installedCodeOwner); + CompilationResult result = tasm.finishTargetMethod(lirGen.getGraph()); if (!assumptions.isEmpty()) { result.setAssumptions(assumptions); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Mon May 13 17:11:31 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -94,6 +95,24 @@ return filter != null && filter.matches(currentScope); } + /** + * Extracts a {@link JavaMethod} from an opaque debug context. + * + * @return the {@link JavaMethod} represented by {@code context} or null + */ + public static JavaMethod asJavaMethod(Object context) { + if (context instanceof JavaMethod) { + return (JavaMethod) context; + } + if (context instanceof StructuredGraph) { + ResolvedJavaMethod method = ((StructuredGraph) context).method(); + if (method != null) { + return method; + } + } + return null; + } + private boolean checkMethodFilter() { if (methodFilter == null && extraFilters.isEmpty()) { return true; @@ -102,9 +121,10 @@ if (extraFilters.contains(o)) { return true; } else if (methodFilter != null) { - if (o instanceof JavaMethod) { + JavaMethod method = asJavaMethod(o); + if (method != null) { for (MethodFilter filter : methodFilter) { - if (filter.matches((JavaMethod) o)) { + if (filter.matches(method)) { return true; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Mon May 13 17:11:31 2013 +0200 @@ -430,7 +430,7 @@ /** * The kind of this interval. */ - private Kind kind; + private PlatformKind kind; /** * The head of the list of ranges describing this interval. This list is sorted by @@ -501,15 +501,15 @@ void assignLocation(AllocatableValue newLocation) { if (isRegister(newLocation)) { assert this.location == null : "cannot re-assign location for " + this; - if (newLocation.getKind() == Kind.Illegal && kind != Kind.Illegal) { + if (newLocation.getPlatformKind() == Kind.Illegal && kind != Kind.Illegal) { this.location = asRegister(newLocation).asValue(kind); return; } } else { assert this.location == null || isRegister(this.location) : "cannot re-assign location for " + this; assert isStackSlot(newLocation); - assert newLocation.getKind() != Kind.Illegal; - assert newLocation.getKind() == this.kind; + assert newLocation.getPlatformKind() != Kind.Illegal; + assert newLocation.getPlatformKind() == this.kind; } this.location = newLocation; } @@ -522,14 +522,13 @@ return location; } - public Kind kind() { + public PlatformKind kind() { assert !isRegister(operand) : "cannot access type for fixed interval"; return kind; } - void setKind(Kind kind) { + void setKind(PlatformKind kind) { assert isRegister(operand) || this.kind() == Kind.Illegal || this.kind() == kind : "overwriting existing type"; - assert kind == kind.getStackKind() || kind == Kind.Short : "these kinds should have int type registers"; this.kind = kind; } @@ -714,12 +713,12 @@ assert i1.splitParent() == this : "not a split child of this interval"; assert i1.kind() == kind() : "must be equal for all split children"; - assert i1.spillSlot() == spillSlot() : "must be equal for all split children"; + assert (i1.spillSlot() == null && spillSlot == null) || i1.spillSlot().equals(spillSlot()) : "must be equal for all split children"; for (int j = i + 1; j < splitChildren.size(); j++) { Interval i2 = splitChildren.get(j); - assert i1.operand != i2.operand : "same register number"; + assert !i1.operand.equals(i2.operand) : "same register number"; if (i1.from() < i2.from()) { assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping"; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Mon May 13 17:11:31 2013 +0200 @@ -56,7 +56,6 @@ public final class LinearScan { final TargetDescription target; - final JavaMethod method; final LIR ir; final LIRGenerator gen; final FrameMap frameMap; @@ -156,9 +155,8 @@ */ private final int firstVariableNumber; - public LinearScan(TargetDescription target, ResolvedJavaMethod method, LIR ir, LIRGenerator gen, FrameMap frameMap) { + public LinearScan(TargetDescription target, LIR ir, LIRGenerator gen, FrameMap frameMap) { this.target = target; - this.method = method; this.ir = ir; this.gen = gen; this.frameMap = frameMap; @@ -305,7 +303,7 @@ intervals = Arrays.copyOf(intervals, intervals.length * 2); } intervalsSize++; - Variable variable = new Variable(source.kind(), ir.nextVariable(), asVariable(source.operand).flag); + Variable variable = new Variable(source.kind(), ir.nextVariable()); assert variables.size() == variable.index; variables.add(variable); @@ -413,7 +411,7 @@ */ boolean hasCall(int opId) { assert isEven(opId) : "opId not even"; - return instructionForId(opId).hasCall(); + return instructionForId(opId).destroysCallerSavedRegisters(); } /** @@ -884,7 +882,7 @@ } private void reportFailure(int numBlocks) { - TTY.println(method.toString()); + TTY.println(gen.getGraph().toString()); TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined)"); TTY.print("affected registers:"); TTY.println(blockData.get(ir.cfg.getStartBlock()).liveIn.toString()); @@ -968,7 +966,7 @@ TTY.println(blockData.get(block).liveOut.toString()); } - void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, Kind kind) { + void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, PlatformKind kind) { if (!isProcessed(operand)) { return; } @@ -987,7 +985,7 @@ interval.addUsePos(to & ~1, registerPriority); } - void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, Kind kind) { + void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, PlatformKind kind) { if (!isProcessed(operand)) { return; } @@ -1008,7 +1006,7 @@ return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable(); } - void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, Kind kind) { + void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, PlatformKind kind) { if (!isProcessed(operand)) { return; } @@ -1181,7 +1179,7 @@ final int opId = op.id(); // add a temp range for each register if operation destroys caller-save registers - if (op.hasCall()) { + if (op.destroysCallerSavedRegisters()) { for (Register r : callerSaveRegs) { if (attributes(r).isAllocatable()) { addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); @@ -1197,7 +1195,7 @@ @Override public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { - addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind()); + addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getPlatformKind()); addRegisterHint(op, operand, mode, flags, true); } return operand; @@ -1208,7 +1206,7 @@ @Override public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { - addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind()); + addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1220,7 +1218,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1232,7 +1230,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind()); addRegisterHint(op, operand, mode, flags, false); } return operand; @@ -1247,7 +1245,7 @@ @Override public Value doValue(Value operand) { - addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getKind().getStackKind()); + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind()); return operand; } }); @@ -1483,7 +1481,7 @@ Interval fromInterval = intervalAtBlockEnd(fromBlock, liveOperand); Interval toInterval = intervalAtBlockBegin(toBlock, liveOperand); - if (fromInterval != toInterval && (fromInterval.location() != toInterval.location())) { + if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { // need to insert move instruction moveResolver.addMapping(fromInterval, toInterval); } @@ -1681,7 +1679,7 @@ // before we've consumed the inputs. if (op.id() < interval.currentTo()) { // caller-save registers must not be included into oop-maps at calls - assert !op.hasCall() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; + assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; frameMap.setReference(interval.location(), registerRefMap, frameRefMap); @@ -1703,7 +1701,7 @@ } private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) { - BitSet registerRefMap = op.hasCall() ? null : frameMap.initRegisterRefMap(); + BitSet registerRefMap = op.destroysCallerSavedRegisters() ? null : frameMap.initRegisterRefMap(); BitSet frameRefMap = frameMap.initFrameRefMap(); computeOopMap(iw, op, registerRefMap, frameRefMap); @@ -1782,7 +1780,7 @@ // remove useless moves if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; - if (move.getInput() == move.getResult()) { + if (move.getInput().equals(move.getResult())) { instructions.set(j, null); hasDead = true; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,6 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.alloc.Interval.RegisterBinding; import com.oracle.graal.compiler.alloc.Interval.RegisterPriority; @@ -811,14 +810,15 @@ } void initVarsForAlloc(Interval interval) { - EnumMap categorizedRegs = allocator.frameMap.registerConfig.getCategorizedAllocatableRegisters(); - availableRegs = categorizedRegs.get(asVariable(interval.operand).flag); + availableRegs = allocator.frameMap.registerConfig.getAllocatableRegisters(interval.kind()); } static boolean isMove(LIRInstruction op, Interval from, Interval to) { if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; - return isVariable(move.getInput()) && isVariable(move.getResult()) && move.getInput() == from.operand && move.getResult() == to.operand; + if (isVariable(move.getInput()) && isVariable(move.getResult())) { + return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand); + } } return false; } @@ -936,7 +936,7 @@ if (interval.insertMoveWhenActivated()) { assert interval.isSplitChild(); assert interval.currentSplitChild() != null; - assert interval.currentSplitChild().operand != operand : "cannot insert move between same interval"; + assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; if (GraalOptions.TraceLinearScanLevel >= 4) { TTY.println("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java Mon May 13 17:11:31 2013 +0200 @@ -134,7 +134,7 @@ } for (i = 0; i < mappingTo.size(); i++) { Interval interval = mappingTo.get(i); - assert !usedRegs.contains(interval.location()) || interval.location() == mappingFrom.get(i).location() : "stack slots used in mappingFrom must be disjoint to mappingTo"; + assert !usedRegs.contains(interval.location()) || interval.location().equals(mappingFrom.get(i).location()) : "stack slots used in mappingFrom must be disjoint to mappingTo"; } return true; @@ -169,7 +169,7 @@ Value reg = to.location(); if (isRegister(reg)) { - if (registerBlocked(asRegister(reg).number) > 1 || (registerBlocked(asRegister(reg).number) == 1 && reg != fromReg)) { + if (registerBlocked(asRegister(reg).number) > 1 || (registerBlocked(asRegister(reg).number) == 1 && !reg.equals(fromReg))) { return false; } } @@ -192,7 +192,7 @@ } private void insertMove(Interval fromInterval, Interval toInterval) { - assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; + assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval; assert fromInterval.kind() == toInterval.kind() : "move between different types"; assert insertIdx != -1 : "must setup insert position first"; @@ -207,7 +207,7 @@ } private void insertMove(Value fromOpr, Interval toInterval) { - assert fromOpr.getKind() == toInterval.kind() : "move between different types"; + assert fromOpr.getPlatformKind() == toInterval.kind() : "move between different types"; assert insertIdx != -1 : "must setup insert position first"; AllocatableValue toOpr = toInterval.operand; @@ -331,7 +331,7 @@ TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); } - assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; + assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval; assert fromInterval.kind() == toInterval.kind(); mappingFrom.add(fromInterval); mappingFromOpr.add(Value.ILLEGAL); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Mon May 13 17:11:31 2013 +0200 @@ -248,7 +248,7 @@ // check if input operands are correct op.forEachInput(useProc); // invalidate all caller save registers at calls - if (op.hasCall()) { + if (op.destroysCallerSavedRegisters()) { for (Register r : allocator.frameMap.registerConfig.getCallerSaveRegisters()) { statePut(inputState, r.asValue(), null); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon May 13 17:11:31 2013 +0200 @@ -165,7 +165,6 @@ throw new GraalInternalError("no mapping found for virtual object %s", obj); } if (state instanceof MaterializedObjectState) { - assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode); return toValue(((MaterializedObjectState) state).materializedValue()); } else { assert obj.entryCount() == 0 || state instanceof VirtualObjectState; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -61,7 +61,7 @@ protected final StructuredGraph graph; protected final CodeCacheProvider runtime; protected final TargetDescription target; - protected final ResolvedJavaMethod method; + protected final CallingConvention cc; protected final DebugInfoBuilder debugInfoBuilder; @@ -85,12 +85,18 @@ */ public abstract boolean canStoreConstant(Constant c); - public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { + public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { this.graph = graph; this.runtime = runtime; this.target = target; this.frameMap = frameMap; - this.method = method; + if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { + this.cc = cc; + } else { + JavaType[] parameterTypes = new JavaType[]{runtime.lookupJavaType(long.class)}; + CallingConvention tmp = frameMap.registerConfig.getCallingConvention(JavaCallee, runtime.lookupJavaType(void.class), parameterTypes, target, false); + this.cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0)); + } this.nodeOperands = graph.createNodeMap(); this.lir = lir; this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); @@ -112,8 +118,8 @@ return runtime; } - public ResolvedJavaMethod method() { - return method; + public StructuredGraph getGraph() { + return graph; } /** @@ -132,7 +138,7 @@ public ValueNode valueForOperand(Value value) { for (Entry entry : nodeOperands.entries()) { - if (entry.getValue() == value) { + if (entry.getValue().equals(value)) { return (ValueNode) entry.getKey(); } } @@ -142,23 +148,18 @@ /** * Creates a new {@linkplain Variable variable}. * - * @param kind The kind of the new variable. + * @param platformKind The kind of the new variable. * @return a new variable */ @Override - public Variable newVariable(Kind kind) { - Kind stackKind = kind.getStackKind(); - switch (stackKind) { - case Int: - case Long: - case Object: - return new Variable(stackKind, lir.nextVariable(), Register.RegisterFlag.CPU); - case Float: - case Double: - return new Variable(stackKind, lir.nextVariable(), Register.RegisterFlag.FPU); - default: - throw GraalInternalError.shouldNotReachHere(); + public Variable newVariable(PlatformKind platformKind) { + PlatformKind stackKind; + if (platformKind instanceof Kind) { + stackKind = ((Kind) platformKind).getStackKind(); + } else { + stackKind = platformKind; } + return new Variable(stackKind, lir.nextVariable()); } @Override @@ -428,12 +429,8 @@ ((LIRLowerable) node).generate(this); } - protected CallingConvention createCallingConvention() { - return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), MetaUtil.signatureToTypes(method), target, false); - } - protected void emitPrologue() { - CallingConvention incomingArguments = createCallingConvention(); + CallingConvention incomingArguments = cc; Value[] params = new Value[incomingArguments.getArgumentCount()]; for (int i = 0; i < params.length; i++) { @@ -476,7 +473,7 @@ } @Override - public void visitEndNode(EndNode end) { + public void visitEndNode(AbstractEndNode end) { moveToPhi(end.merge(), end); } @@ -487,7 +484,7 @@ public void visitLoopEnd(LoopEndNode x) { } - private void moveToPhi(MergeNode merge, EndNode pred) { + private void moveToPhi(MergeNode merge, AbstractEndNode pred) { if (GraalOptions.TraceLIRGeneratorLevel >= 1) { TTY.println("MOVE TO PHI from " + pred + " to " + merge); } @@ -599,10 +596,10 @@ @Override public void emitInvoke(Invoke x) { LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); - CallingConvention cc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(runtime), callTarget.signature(), target(), false); - frameMap.callsMethod(cc); + CallingConvention invokeCc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(runtime), callTarget.signature(), target(), false); + frameMap.callsMethod(invokeCc); - Value[] parameters = visitInvokeArguments(cc, callTarget.arguments()); + Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); LabelRef exceptionEdge = null; if (x instanceof InvokeWithExceptionNode) { @@ -610,11 +607,11 @@ } LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); - Value result = cc.getReturn(); + Value result = invokeCc.getReturn(); if (callTarget instanceof DirectCallTargetNode) { - emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, cc.getTemporaries(), callState); + emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState); } else if (callTarget instanceof IndirectCallTargetNode) { - emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, cc.getTemporaries(), callState); + emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, invokeCc.getTemporaries(), callState); } else { throw GraalInternalError.shouldNotReachHere(); } @@ -645,13 +642,13 @@ return value; } - public Value[] visitInvokeArguments(CallingConvention cc, Collection arguments) { + public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection arguments) { // for each argument, load it into the correct location Value[] result = new Value[arguments.size()]; int j = 0; for (ValueNode arg : arguments) { if (arg != null) { - AllocatableValue operand = toStackKind(cc.getArgument(j)); + AllocatableValue operand = toStackKind(invokeCc.getArgument(j)); emitMove(operand, operand(arg)); result[j] = operand; j++; @@ -663,23 +660,23 @@ } @Override - public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) { + public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) { LIRFrameState state = info != null ? state(info) : null; // move the arguments into the correct location - frameMap.callsMethod(cc); - assert cc.getArgumentCount() == args.length : "argument count mismatch"; + frameMap.callsMethod(callCc); + assert callCc.getArgumentCount() == args.length : "argument count mismatch"; Value[] argLocations = new Value[args.length]; for (int i = 0; i < args.length; i++) { Value arg = args[i]; - AllocatableValue loc = cc.getArgument(i); + AllocatableValue loc = callCc.getArgument(i); emitMove(loc, arg); argLocations[i] = loc; } - emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), state); + emitCall(callTarget, callCc.getReturn(), argLocations, callCc.getTemporaries(), state); - if (isLegal(cc.getReturn())) { - return emitMove(cc.getReturn()); + if (isLegal(callCc.getReturn())) { + return emitMove(callCc.getReturn()); } else { return null; } @@ -688,12 +685,12 @@ @Override public void visitRuntimeCall(RuntimeCallNode x) { RuntimeCallTarget call = runtime.lookupRuntimeCall(x.getDescriptor()); - CallingConvention cc = call.getCallingConvention(); - frameMap.callsMethod(cc); - Value resultOperand = cc.getReturn(); - Value[] args = visitInvokeArguments(cc, x.arguments()); + CallingConvention callCc = call.getCallingConvention(); + frameMap.callsMethod(callCc); + Value resultOperand = callCc.getReturn(); + Value[] args = visitInvokeArguments(callCc, x.arguments()); - emitCall(call, resultOperand, args, cc.getTemporaries(), state(x)); + emitCall(call, resultOperand, args, callCc.getTemporaries(), state(x)); if (isLegal(resultOperand)) { setResult(x, emitMove(resultOperand)); @@ -830,6 +827,35 @@ public void beforeRegisterAllocation() { } + /** + * Gets an garbage vale for a given kind. + */ + protected Constant zapValueForKind(PlatformKind kind) { + long dead = 0xDEADDEADDEADDEADL; + switch ((Kind) kind) { + case Boolean: + return Constant.FALSE; + case Byte: + return Constant.forByte((byte) dead); + case Char: + return Constant.forChar((char) dead); + case Short: + return Constant.forShort((short) dead); + case Int: + return Constant.forInt((int) dead); + case Double: + return Constant.forDouble(Double.longBitsToDouble(dead)); + case Float: + return Constant.forFloat(Float.intBitsToFloat((int) dead)); + case Long: + return Constant.forLong(dead); + case Object: + return Constant.NULL_OBJECT; + default: + throw new IllegalArgumentException(kind.toString()); + } + } + public abstract void emitBitCount(Variable result, Value operand); public abstract void emitBitScanForward(Variable result, Value operand); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Mon May 13 17:11:31 2013 +0200 @@ -34,16 +34,10 @@ public HighTier() { if (GraalOptions.FullUnroll) { addPhase(new LoopFullUnrollPhase()); - if (GraalOptions.OptCanonicalizer) { - addPhase(new CanonicalizerPhase()); - } } if (GraalOptions.OptTailDuplication) { addPhase(new TailDuplicationPhase()); - if (GraalOptions.OptCanonicalizer) { - addPhase(new CanonicalizerPhase()); - } } if (GraalOptions.PartialEscapeAnalysis) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Mon May 13 17:11:31 2013 +0200 @@ -34,6 +34,8 @@ addPhase(new FrameStateAssignmentPhase()); + addPhase(new ExpandLogicPhase()); + addPhase(new DeadCodeEliminationPhase()); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.compiler.phases; +import com.oracle.graal.loop.phases.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; @@ -66,7 +67,8 @@ addPhase(new CanonicalizerPhase()); } - // Add safepoints to loops + addPhase(new LoopSafepointEliminationPhase()); + addPhase(new SafepointInsertionPhase()); addPhase(new GuardLoweringPhase()); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Mon May 13 17:11:31 2013 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -50,15 +51,18 @@ return new FrameMap(runtime, target, runtime.lookupRegisterConfig()); } - public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir); + public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir); + + protected abstract AbstractAssembler createAssembler(FrameMap frameMap); public abstract TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult); /** - * Emits the code for a given method. This includes any architecture/runtime specific - * prefix/suffix. A prefix typically contains the code for setting up the frame, spilling - * callee-save registers, stack overflow checking, handling multiple entry points etc. A suffix - * may contain out-of-line stubs and method end guard instructions. + * Emits the code for a given graph. + * + * @param installedCodeOwner the method the compiled code will be + * {@linkplain InstalledCode#getMethod() associated} with once installed. This + * argument can be null. */ - public abstract void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen); + public abstract void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Mon May 13 17:11:31 2013 +0200 @@ -47,7 +47,8 @@ private int deletedNodeCount; private GraphEventLog eventLog; - InputChangedListener inputChanged; + NodeChangedListener inputChanged; + NodeChangedListener usagesDroppedZero; private final HashMap cachedNodes = new HashMap<>(); private static final class CacheEntry { @@ -152,12 +153,12 @@ return node; } - public interface InputChangedListener { + public interface NodeChangedListener { - void inputChanged(Node node); + void nodeChanged(Node node); } - public void trackInputChange(InputChangedListener inputChangedListener) { + public void trackInputChange(NodeChangedListener inputChangedListener) { this.inputChanged = inputChangedListener; } @@ -165,6 +166,14 @@ inputChanged = null; } + public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) { + this.usagesDroppedZero = usagesDroppedZeroListener; + } + + public void stopTrackingUsagesDroppedZero() { + usagesDroppedZero = null; + } + /** * Adds a new node to the graph, if a similar node already exists in the graph, the * provided node will not be added to the graph but the similar node will be returned @@ -468,7 +477,11 @@ } public NodeMap createNodeMap() { - return new NodeMap<>(this); + return createNodeMap(false); + } + + public NodeMap createNodeMap(boolean autoGrow) { + return new NodeMap<>(this, autoGrow); } public NodeFlood createNodeFlood() { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon May 13 17:11:31 2013 +0200 @@ -25,7 +25,7 @@ import java.lang.annotation.*; import java.util.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.NodeClass.*; import com.oracle.graal.graph.iterators.*; @@ -193,12 +193,17 @@ assert assertTrue(result, "not found in usages, old input: %s", oldInput); } if (newInput != null) { - InputChangedListener inputChanged = graph.inputChanged; + NodeChangedListener inputChanged = graph.inputChanged; if (inputChanged != null) { - inputChanged.inputChanged(this); + inputChanged.nodeChanged(this); } assert newInput.usages != null : "not yet added? " + newInput; newInput.usages.add(this); + } else if (oldInput != null && oldInput.usages().isEmpty()) { + NodeChangedListener nodeChangedListener = graph.usagesDroppedZero; + if (nodeChangedListener != null) { + nodeChangedListener.nodeChanged(oldInput); + } } } } @@ -253,9 +258,9 @@ boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { - InputChangedListener inputChanged = graph.inputChanged; + NodeChangedListener inputChanged = graph.inputChanged; if (inputChanged != null) { - inputChanged.inputChanged(usage); + inputChanged.nodeChanged(usage); } other.usages.add(usage); } @@ -299,6 +304,12 @@ for (Node input : inputs()) { removeThisFromUsages(input); + if (input.usages().isEmpty()) { + NodeChangedListener nodeChangedListener = graph.usagesDroppedZero; + if (nodeChangedListener != null) { + nodeChangedListener.nodeChanged(input); + } + } } getNodeClass().clearInputs(this); } @@ -447,7 +458,7 @@ * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the * ideal graph visualizer). */ - public Map getDebugProperties() { + public final Map getDebugProperties() { return getDebugProperties(new HashMap<>()); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Mon May 13 17:11:31 2013 +0200 @@ -192,7 +192,7 @@ if (INPUT_LIST_CLASS.isAssignableFrom(type)) { inputListOffsets.add(offset); } else { - assert NODE_CLASS.isAssignableFrom(type) : "invalid input type: " + type; + assert NODE_CLASS.isAssignableFrom(type) || type.isInterface() : "invalid input type: " + type; inputOffsets.add(offset); } if (field.getAnnotation(Node.Input.class).notDataflow()) { @@ -759,8 +759,11 @@ } public boolean edgesEqual(Node node, Node other) { + return inputsEqual(node, other) && successorsEqual(node, other); + } + + public boolean inputsEqual(Node node, Node other) { assert node.getClass() == clazz && other.getClass() == clazz; - int index = 0; while (index < directInputCount) { if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) { @@ -775,8 +778,12 @@ } index++; } + return true; + } - index = 0; + public boolean successorsEqual(Node node, Node other) { + assert node.getClass() == clazz && other.getClass() == clazz; + int index = 0; while (index < directSuccessorCount) { if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) { return false; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Mon May 13 17:11:31 2013 +0200 @@ -29,19 +29,23 @@ public final class NodeMap { private final Graph graph; + private final boolean autogrow; private Object[] values; - private int size; public NodeMap(Graph graph) { + this(graph, false); + } + + public NodeMap(Graph graph, boolean autogrow) { this.graph = graph; - values = new Object[graph.nodeIdCount()]; - size = values.length; + this.values = new Object[graph.nodeIdCount()]; + this.autogrow = autogrow; } public NodeMap(NodeMap copyFrom) { this.graph = copyFrom.graph; this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length); - this.size = copyFrom.size; + this.autogrow = copyFrom.autogrow; } @SuppressWarnings("unchecked") @@ -60,14 +64,21 @@ } public int size() { - return size; + return values.length; } public boolean isNew(Node node) { - return node.id() >= size; + return node.id() >= size(); + } + + public void grow() { + this.values = Arrays.copyOf(values, graph.nodeIdCount()); } private void check(Node node) { + if (autogrow && isNew(node)) { + grow(); + } assert node.graph() == graph : "this node is not part of the graph"; assert !isNew(node) : "this node was added to the graph after creating the node map : " + node; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java --- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Mon May 13 17:11:31 2013 +0200 @@ -30,7 +30,6 @@ import org.junit.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.asm.amd64.*; @@ -71,7 +70,7 @@ @Override public void generateCode(AMD64Assembler asm) { - Register arg = getArgumentRegister(0, RegisterFlag.CPU); + Register arg = getArgumentRegister(0, Kind.Int); asm.addl(arg, 5); asm.movl(rax, arg); asm.ret(0); @@ -89,7 +88,7 @@ @Override public void generateCode(AMD64Assembler asm) { - Register arg = getArgumentRegister(0, RegisterFlag.CPU); + Register arg = getArgumentRegister(0, Kind.Long); asm.addq(arg, 1); asm.movq(rax, arg); asm.ret(0); @@ -117,8 +116,8 @@ Assert.assertArrayEquals(expectedCode, actualCode); } - private Register getArgumentRegister(int index, RegisterFlag flag) { - Register[] regs = runtime.lookupRegisterConfig().getCallingConventionRegisters(CallingConvention.Type.JavaCall, flag); + private Register getArgumentRegister(int index, Kind kind) { + Register[] regs = runtime.lookupRegisterConfig().getCallingConventionRegisters(CallingConvention.Type.JavaCall, kind); return regs[index]; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Mon May 13 17:11:31 2013 +0200 @@ -22,23 +22,21 @@ */ package com.oracle.graal.hotspot.amd64; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; @Opcode("DEOPT") final class AMD64DeoptimizeOp extends AMD64LIRInstruction { - public static final Descriptor DEOPTIMIZE = new Descriptor("deoptimize", true, void.class); - private DeoptimizationAction action; private DeoptimizationReason reason; @State private LIRFrameState info; @@ -54,6 +52,6 @@ HotSpotGraalRuntime runtime = graalRuntime(); Register thread = runtime.getRuntime().threadRegister(); masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), null, false, info); + AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP), null, false, info); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon May 13 17:11:31 2013 +0200 @@ -26,15 +26,14 @@ import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.phases.GraalOptions.*; +import static java.lang.reflect.Modifier.*; -import java.lang.reflect.*; import java.util.*; import sun.misc.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; @@ -45,7 +44,8 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; +import com.oracle.graal.lir.StandardOp.ParametersOp; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; @@ -58,17 +58,14 @@ public class AMD64HotSpotBackend extends HotSpotBackend { private static final Unsafe unsafe = Unsafe.getUnsafe(); - public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class); - public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class); - public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class); public AMD64HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) { super(runtime, target); } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - return new AMD64HotSpotLIRGenerator(graph, runtime(), target, frameMap, method, lir); + public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) { + return new AMD64HotSpotLIRGenerator(graph, runtime(), target, frameMap, cc, lir); } /** @@ -99,13 +96,21 @@ class HotSpotFrameContext implements FrameContext { + final boolean isStub; + + HotSpotFrameContext(boolean isStub) { + this.isStub = isStub; + } + @Override public void enter(TargetMethodAssembler tasm) { FrameMap frameMap = tasm.frameMap; int frameSize = frameMap.frameSize(); AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; - emitStackOverflowCheck(tasm, false); + if (!isStub) { + emitStackOverflowCheck(tasm, false); + } asm.decrementq(rsp, frameSize); if (GraalOptions.ZapStackOnMethodEntry) { final int intSize = 4; @@ -139,6 +144,11 @@ } @Override + protected AbstractAssembler createAssembler(FrameMap frameMap) { + return new AMD64MacroAssembler(target, frameMap.registerConfig); + } + + @Override public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { // Omit the frame if the method: // - has no spill slots or other slots allocated during register allocation @@ -150,53 +160,75 @@ LIR lir = gen.lir; boolean omitFrame = CanOmitFrame && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame(); - AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig); - HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(); + Stub stub = gen.getStub(); + AbstractAssembler masm = createAssembler(frameMap); + HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(stub != null); TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); tasm.setFrameSize(frameMap.frameSize()); StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot; - if (deoptimizationRescueSlot != null) { + if (deoptimizationRescueSlot != null && stub == null) { tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot)); } - Stub stub = runtime().asStub(lirGen.method()); if (stub != null) { - final Set definedRegisters = new HashSet<>(); - ValueProcedure defProc = new ValueProcedure() { + + final Set definedRegisters = gatherDefinedRegisters(lir); + stub.initDestroyedRegisters(definedRegisters); - @Override - public Value doValue(Value value) { - if (ValueUtil.isRegister(value)) { - final Register reg = ValueUtil.asRegister(value); - definedRegisters.add(reg); - } - return value; - } - }; - for (Block block : lir.codeEmittingOrder()) { - for (LIRInstruction op : lir.lir(block)) { - op.forEachTemp(defProc); - op.forEachOutput(defProc); - } + // Eliminate unnecessary register preservation and + // record where preserved registers are saved + for (Map.Entry e : gen.calleeSaveInfo.entrySet()) { + AMD64RegistersPreservationOp save = e.getValue(); + save.update(definedRegisters, e.getKey().debugInfo(), frameMap); } - stub.initDefinedRegisters(definedRegisters); } return tasm; } + /** + * Finds all the registers that are defined by some given LIR. + * + * @param lir the LIR to examine + * @return the registers that are defined by or used as temps for any instruction in {@code lir} + */ + private static Set gatherDefinedRegisters(LIR lir) { + final Set definedRegisters = new HashSet<>(); + ValueProcedure defProc = new ValueProcedure() { + + @Override + public Value doValue(Value value) { + if (ValueUtil.isRegister(value)) { + final Register reg = ValueUtil.asRegister(value); + definedRegisters.add(reg); + } + return value; + } + }; + for (Block block : lir.codeEmittingOrder()) { + for (LIRInstruction op : lir.lir(block)) { + if (op instanceof ParametersOp) { + // Don't consider this as a definition + } else { + op.forEachTemp(defProc); + op.forEachOutput(defProc); + } + } + } + return definedRegisters; + } + @Override - public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { + public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod installedCodeOwner) { AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; FrameMap frameMap = tasm.frameMap; RegisterConfig regConfig = frameMap.registerConfig; HotSpotVMConfig config = runtime().config; - boolean isStatic = Modifier.isStatic(method.getModifiers()); - Label unverifiedStub = isStatic ? null : new Label(); + Label unverifiedStub = installedCodeOwner == null || isStatic(installedCodeOwner.getModifiers()) ? null : new Label(); // Emit the prefix - if (!isStatic) { + if (unverifiedStub != null) { tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY); CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false); Register inlineCacheKlass = rax; // see definition of IC_Klass in @@ -215,8 +247,8 @@ // Emit code for the LIR lirGen.lir.emitCode(tasm); - boolean frameOmitted = tasm.frameContext == null; - if (!frameOmitted) { + HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext; + if (frameContext != null && !frameContext.isStub) { tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY); AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null); tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY); @@ -224,7 +256,7 @@ } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries - assert !frameMap.accessesCallerFrame() : method; + assert !frameMap.accessesCallerFrame() : lirGen.getGraph(); } if (unverifiedStub != null) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("CRUNTIME_CALL_EPILOGUE") +final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction { + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // reset last Java frame: + HotSpotVMConfig config = graalRuntime().getConfig(); + Register thread = graalRuntime().getRuntime().threadRegister(); + + masm.movslq(new AMD64Address(thread, config.threadLastJavaSpOffset), 0); + masm.movslq(new AMD64Address(thread, config.threadLastJavaFpOffset), 0); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("CRUNTIME_CALL_PROLOGUE") +final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction { + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + + // save last Java frame + Register thread = graalRuntime().getRuntime().threadRegister(); + masm.movq(new AMD64Address(thread, graalRuntime().getConfig().threadLastJavaSpOffset), rsp); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.hotspot.HotSpotBackend.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@Opcode("DEOPT_CALLER") +final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp { + + private final DeoptimizationAction action; + private final DeoptimizationReason reason; + + AMD64HotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) { + this.action = action; + this.reason = reason; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(tasm, masm); + + HotSpotGraalRuntime runtime = graalRuntime(); + Register thread = runtime.getRuntime().threadRegister(); + masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); + AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(UNCOMMON_TRAP)); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java Mon May 13 17:11:31 2013 +0200 @@ -22,12 +22,16 @@ */ 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.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; /** * Superclass for operations that use the value of RBP saved in a method's prologue. @@ -39,7 +43,22 @@ * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR * verification is successful. */ - private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE, Register.RegisterFlag.CPU); + private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE); @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER; + + protected void leaveFrameAndRestoreRbp(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + if (isStackSlot(savedRbp)) { + // Restoring RBP from the stack must be done before the frame is removed + masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); + } else { + Register framePointer = asRegister(savedRbp); + if (framePointer != rbp) { + masm.movq(rbp, framePointer); + } + } + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Mon May 13 17:11:31 2013 +0200 @@ -30,9 +30,9 @@ /** * AMD64 specific implementation of {@link HotSpotGraalRuntime}. */ -final class AMD64HotSpotGraalRuntime extends HotSpotGraalRuntime { +public class AMD64HotSpotGraalRuntime extends HotSpotGraalRuntime { - private AMD64HotSpotGraalRuntime() { + protected AMD64HotSpotGraalRuntime() { } /** @@ -40,16 +40,25 @@ */ public static HotSpotGraalRuntime makeInstance() { if (graalRuntime() == null) { - setInstance(new AMD64HotSpotGraalRuntime()); + HotSpotGraalRuntimeFactory factory = findFactory("AMD64"); + if (factory != null) { + setInstance(factory.createRuntime()); + } else { + setInstance(new AMD64HotSpotGraalRuntime()); + } } return graalRuntime(); } + protected Architecture createArchitecture() { + return new AMD64(config.useSSE, config.useAVX); + } + @Override protected TargetDescription createTarget() { final int stackFrameAlignment = 16; final int implicitNullCheckLimit = 4096; - return new TargetDescription(new AMD64(config.useSSE, config.useAVX), true, stackFrameAlignment, implicitNullCheckLimit, true); + return new TargetDescription(createArchitecture(), true, stackFrameAlignment, implicitNullCheckLimit, true); } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Sets up the arguments for an exception handler in the callers frame, removes the current frame + * and jumps to the handler. + */ +@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") +final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp { + + @Use(REG) AllocatableValue handlerInCallerPc; + @Use(REG) AllocatableValue exception; + @Use(REG) AllocatableValue exceptionPc; + + AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc) { + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + leaveFrameAndRestoreRbp(tasm, masm); + + // Discard the return address, thus completing restoration of caller frame + masm.incrementq(rsp, 8); + + // Restore rsp from rbp if the exception PC is a method handle call site. + Register thread = graalRuntime().getRuntime().threadRegister(); + int isMethodHandleReturnOffset = graalRuntime().getConfig().threadIsMethodHandleReturnOffset; + AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset); + masm.cmpl(dst, 0); + masm.cmovq(ConditionFlag.NotEqual, rsp, rbp); + + masm.jmp(asRegister(handlerInCallerPc)); + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -23,9 +23,8 @@ package com.oracle.graal.hotspot.amd64; import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import java.lang.reflect.*; import java.util.*; @@ -54,14 +53,14 @@ /** * LIR generator specialized for AMD64 HotSpot. */ -final class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { +public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { private HotSpotRuntime runtime() { return (HotSpotRuntime) runtime; } - AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - super(graph, runtime, target, frameMap, method, lir); + protected AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { + super(graph, runtime, target, frameMap, cc, lir); } /** @@ -115,6 +114,14 @@ */ List epilogueOps = new ArrayList<>(2); + @Override + public void append(LIRInstruction op) { + super.append(op); + if (op instanceof AMD64HotSpotEpilogueOp) { + epilogueOps.add((AMD64HotSpotEpilogueOp) op); + } + } + @SuppressWarnings("hiding") @Override protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { @@ -131,7 +138,7 @@ @Override protected void emitPrologue() { - CallingConvention incomingArguments = createCallingConvention(); + CallingConvention incomingArguments = cc; RegisterValue rbpParam = rbp.asValue(Kind.Long); Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; @@ -145,8 +152,8 @@ } } params[params.length - 1] = rbpParam; + ParametersOp paramsOp = new ParametersOp(params); - ParametersOp paramsOp = new ParametersOp(params); append(paramsOp); saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size())); @@ -161,29 +168,102 @@ @Override protected void emitReturn(Value input) { - AMD64HotSpotReturnOp op = new AMD64HotSpotReturnOp(input); - epilogueOps.add(op); - append(op); + append(new AMD64HotSpotReturnOp(input)); } @Override protected boolean needOnlyOopMaps() { // Stubs only need oop maps - return runtime().asStub(method) != null; + return graph.start() instanceof StubStartNode; + } + + /** + * Map from debug infos that need to be updated with callee save information to the operations + * that provide the information. + */ + Map calleeSaveInfo = new HashMap<>(); + + private LIRFrameState currentRuntimeCallInfo; + + @Override + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + currentRuntimeCallInfo = info; + super.emitCall(callTarget, result, arguments, temps, info); + } + + protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlot[] savedRegisterLocations) { + AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations); + append(save); + return save; + } + + protected void emitRestoreRegisters(AMD64SaveRegistersOp save) { + append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save)); + } + + Stub getStub() { + if (graph.start() instanceof StubStartNode) { + return ((StubStartNode) graph.start()).getStub(); + } + return null; } @Override - protected CallingConvention createCallingConvention() { - Stub stub = runtime().asStub(method); - if (stub != null) { - return stub.getLinkage().getCallingConvention(); + public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention callCc, DeoptimizingNode info, Value... args) { + Stub stub = getStub(); + boolean isCRuntimeCall = ((HotSpotRuntimeCallTarget) callTarget).isCRuntimeCall(); + assert !isCRuntimeCall || stub != null : "direct call to C runtime can only be made from compiled stubs, not from " + graph; + + AMD64SaveRegistersOp save = null; + StackSlot[] savedRegisterLocations = null; + if (isCRuntimeCall) { + if (stub.preservesRegisters()) { + Register[] savedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + savedRegisterLocations = new StackSlot[savedRegisters.length]; + for (int i = 0; i < savedRegisters.length; i++) { + PlatformKind kind = target.arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory()); + assert kind != Kind.Illegal; + StackSlot spillSlot = frameMap.allocateSpillSlot(kind); + savedRegisterLocations[i] = spillSlot; + } + save = emitSaveRegisters(savedRegisters, savedRegisterLocations); + } + append(new AMD64HotSpotCRuntimeCallPrologueOp()); } - if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { - return super.createCallingConvention(); - } else { - return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), new JavaType[]{runtime.lookupJavaType(long.class)}, target, false); + Variable result = super.emitCall(callTarget, callCc, info, args); + + if (isCRuntimeCall) { + append(new AMD64HotSpotCRuntimeCallEpilogueOp()); + if (stub.preservesRegisters()) { + assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); + calleeSaveInfo.put(currentRuntimeCallInfo, save); + + emitRestoreRegisters(save); + } else { + assert zapRegisters(); + } } + + return result; + } + + protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) { + AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues); + append(zap); + return zap; + } + + protected boolean zapRegisters() { + Register[] zappedRegisters = frameMap.registerConfig.getAllocatableRegisters(); + Constant[] zapValues = new Constant[zappedRegisters.length]; + for (int i = 0; i < zappedRegisters.length; i++) { + PlatformKind kind = target.arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory()); + assert kind != Kind.Illegal; + zapValues[i] = zapValueForKind(kind); + } + calleeSaveInfo.put(currentRuntimeCallInfo, emitZapRegisters(zappedRegisters, zapValues)); + return true; } @Override @@ -224,7 +304,6 @@ @Override public void emitTailcall(Value[] args, Value address) { append(new AMD64TailcallOp(args, address)); - } @Override @@ -252,11 +331,12 @@ @Override public void emitUnwind(Value exception) { - RegisterValue exceptionParameter = EXCEPTION.asValue(); + RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + CallingConvention stubCc = stub.getCallingConvention(); + assert stubCc.getArgumentCount() == 2; + RegisterValue exceptionParameter = (RegisterValue) stubCc.getArgument(0); emitMove(exceptionParameter, exception); - AMD64HotSpotUnwindOp op = new AMD64HotSpotUnwindOp(exceptionParameter); - epilogueOps.add(op); - append(op); + append(new AMD64HotSpotUnwindOp(exceptionParameter)); } @Override @@ -265,6 +345,30 @@ } @Override + public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { + append(new AMD64HotSpotDeoptimizeCallerOp(action, reason)); + } + + @Override + public void emitPatchReturnAddress(ValueNode address) { + append(new AMD64HotSpotPatchReturnAddressOp(load(operand(address)))); + } + + @Override + public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + Variable handler = load(operand(handlerInCallerPc)); + RuntimeCallTarget stub = getRuntime().lookupRuntimeCall(EXCEPTION_HANDLER_IN_CALLER); + CallingConvention stubCc = stub.getCallingConvention(); + assert stubCc.getArgumentCount() == 2; + RegisterValue exceptionFixed = (RegisterValue) stubCc.getArgument(0); + RegisterValue exceptionPcFixed = (RegisterValue) stubCc.getArgument(1); + emitMove(exceptionFixed, operand(exception)); + emitMove(exceptionPcFixed, operand(exceptionPc)); + AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed); + append(op); + } + + @Override public void beforeRegisterAllocation() { boolean hasDebugInfo = lir.hasDebugInfo(); AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +/** + * Patch the return address of the current frame. + */ +@Opcode("PATCH_RETURN") +final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction { + + @Use(REG) AllocatableValue address; + + AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) { + this.address = address; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + int frameSize = tasm.frameMap.frameSize(); + masm.movq(new AMD64Address(rsp, frameSize), asRegister(address)); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; @@ -38,25 +37,39 @@ // @formatter:off public class AMD64HotSpotRegisterConfig implements RegisterConfig { + private final Architecture architecture; + private final Register[] allocatable = initAllocatable(); - private final EnumMap categorized = Register.categorize(allocatable); + private final HashMap categorized = new HashMap<>(); private final RegisterAttributes[] attributesMap; @Override public Register[] getAllocatableRegisters() { - return allocatable; + return allocatable.clone(); } - @Override - public EnumMap getCategorizedAllocatableRegisters() { - return categorized; + public Register[] getAllocatableRegisters(PlatformKind kind) { + if (categorized.containsKey(kind)) { + return categorized.get(kind); + } + + ArrayList list = new ArrayList<>(); + for (Register reg : getAllocatableRegisters()) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + list.add(reg); + } + } + + Register[] ret = list.toArray(new Register[0]); + categorized.put(kind, ret); + return ret; } @Override public RegisterAttributes[] getAttributesMap() { - return attributesMap; + return attributesMap.clone(); } private final Register[] javaGeneralParameterRegisters; @@ -93,7 +106,9 @@ return allocatable; } - public AMD64HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) { + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, boolean globalStubConfig) { + this.architecture = architecture; + if (config.windowsOs) { javaGeneralParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx}; nativeGeneralParameterRegisters = new Register[] {rcx, rdx, r8, r9}; @@ -109,7 +124,7 @@ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 }; - csl = new CalleeSaveLayout(0, -1, 8, regs); + csl = new CalleeSaveLayout(architecture, 0, -1, 8, regs); } else { csl = null; } @@ -135,10 +150,11 @@ return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); } - public Register[] getCallingConventionRegisters(Type type, RegisterFlag flag) { - if (flag == RegisterFlag.FPU) { + public Register[] getCallingConventionRegisters(Type type, Kind kind) { + if (architecture.canStoreValue(XMM, kind)) { return xmmParameterRegisters; } + assert architecture.canStoreValue(CPU, kind); return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; } @@ -178,7 +194,7 @@ if (locations[i] == null) { locations[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, !type.out); - currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize); + currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Mon May 13 17:11:31 2013 +0200 @@ -22,18 +22,15 @@ */ 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.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.asm.*; /** - * Performs an unwind to throw an exception. + * Returns from a function. */ @Opcode("RETURN") final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp { @@ -46,18 +43,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (isStackSlot(savedRbp)) { - // Restoring RBP from the stack must be done before the frame is removed - masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); - } else { - Register framePointer = asRegister(savedRbp); - if (framePointer != rbp) { - masm.movq(rbp, framePointer); - } - } - if (tasm.frameContext != null) { - tasm.frameContext.leave(tasm); - } + leaveFrameAndRestoreRbp(tasm, masm); masm.ret(0); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Mon May 13 17:11:31 2013 +0200 @@ -23,28 +23,12 @@ package com.oracle.graal.hotspot.amd64; import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*; -import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*; -import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; -import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*; -import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; -import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewArraySlowStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewInstanceSlowStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; -import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*; -import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; -import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; -import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*; -import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*; -import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*; import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*; import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; -import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -62,98 +46,18 @@ Kind word = graalRuntime.getTarget().wordKind; // @formatter:off - addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: exception */ rax.asValue(Kind.Object)); - - addRuntimeCall(DEOPTIMIZE, config.deoptimizeStub, - /* temps */ null, - /* ret */ ret(Kind.Void)); - - addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub, - /* temps */ new Register[]{AMD64.rax}, - /* ret */ ret(Kind.Float), - /* arg0: a */ javaCallingConvention(Kind.Float, - /* arg1: b */ Kind.Float)); - - addRuntimeCall(ARITHMETIC_DREM, config.arithmeticDremStub, - /* temps */ new Register[]{AMD64.rax}, - /* ret */ ret(Kind.Double), - /* arg0: a */ javaCallingConvention(Kind.Double, - /* arg1: b */ Kind.Double)); - - addRuntimeCall(MONITORENTER, config.monitorEnterStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ javaCallingConvention(Kind.Object, - /* arg1: lock */ word)); - - addRuntimeCall(WBPRECALL, config.wbPreCallStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ javaCallingConvention(Kind.Object)); - - addRuntimeCall(WBPOSTCALL, config.wbPostCallStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ javaCallingConvention(Kind.Object, word)); - - addRuntimeCall(MONITOREXIT, config.monitorExitStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ javaCallingConvention(Kind.Object, - /* arg1: lock */ word)); - addStubCall(NEW_ARRAY, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word), - /* arg1: length */ rbx.asValue(Kind.Int)); - - addRuntimeCall(NEW_ARRAY_SLOW, config.newArrayStub, - /* temps */ null, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word), - /* arg1: length */ rbx.asValue(Kind.Int)); - - addStubCall(NEW_INSTANCE, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word)); - - addRuntimeCall(NEW_INSTANCE_SLOW, config.newInstanceStub, - /* temps */ null, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rdx.asValue(word)); + // The calling convention for the exception handler stub is (only?) defined in + // TemplateInterpreterGenerator::generate_throw_exception() + // in templateInterpreter_x86_64.cpp around line 1923 + addStubCall(EXCEPTION_HANDLER, + /* ret */ ret(Kind.Void), + /* arg0: exception */ rax.asValue(Kind.Object), + /* arg1: exceptionPc */ rdx.asValue(word)); - addRuntimeCall(NEW_MULTI_ARRAY, config.newMultiArrayStub, - /* temps */ null, - /* ret */ rax.asValue(Kind.Object), - /* arg0: hub */ rax.asValue(word), - /* arg1: rank */ rbx.asValue(Kind.Int), - /* arg2: dims */ rcx.asValue(word)); - - addRuntimeCall(VERIFY_OOP, config.verifyOopStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ r13.asValue(Kind.Object)); - - addRuntimeCall(VM_ERROR, config.vmErrorStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: where */ javaCallingConvention(Kind.Object, - /* arg1: format */ Kind.Object, - /* arg2: value */ Kind.Long)); - - addRuntimeCall(IDENTITY_HASHCODE, config.identityHashCodeStub, - /* temps */ null, - /* ret */ rax.asValue(Kind.Int), - /* arg0: obj */ javaCallingConvention(Kind.Object)); - - addRuntimeCall(THREAD_IS_INTERRUPTED, config.threadIsInterruptedStub, - /* temps */ null, - /* ret */ rax.asValue(Kind.Boolean), - /* arg0: thread */ javaCallingConvention(Kind.Object, - /* arg1: clearInterrupted */ Kind.Boolean)); + addJump(EXCEPTION_HANDLER_IN_CALLER, + /* arg0: exception */ rax.asValue(Kind.Object), + /* arg1: exceptionPc */ rdx.asValue(word)); addRuntimeCall(ENCRYPT_BLOCK, config.aescryptEncryptBlockStub, /* temps */ null, @@ -186,18 +90,6 @@ /* arg2: key */ word, /* arg3: r */ word, /* arg4: inLength */ Kind.Int)); - - addRuntimeCall(AMD64HotSpotBackend.EXCEPTION_HANDLER, config.handleExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Void)); - - addRuntimeCall(AMD64HotSpotBackend.DEOPT_HANDLER, config.handleDeoptStub, - /* temps */ null, - /* ret */ ret(Kind.Void)); - - addRuntimeCall(AMD64HotSpotBackend.IC_MISS_HANDLER, config.inlineCacheMissStub, - /* temps */ null, - /* ret */ ret(Kind.Void)); // @formatter:on } @@ -231,6 +123,6 @@ @Override protected RegisterConfig createRegisterConfig(boolean globalStubConfig) { - return new AMD64HotSpotRegisterConfig(config, globalStubConfig); + return new AMD64HotSpotRegisterConfig(graalRuntime.getTarget().arch, config, globalStubConfig); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Mon May 13 17:11:31 2013 +0200 @@ -24,53 +24,42 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; /** - * Performs an unwind to throw an exception. + * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. */ @Opcode("UNWIND") final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp { - public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class); + @Use({REG}) protected RegisterValue exception; - /** - * Unwind stub expects the exception in RAX. - */ - public static final Register EXCEPTION = AMD64.rax; - - @Use({REG}) protected AllocatableValue exception; - - AMD64HotSpotUnwindOp(AllocatableValue exception) { + AMD64HotSpotUnwindOp(RegisterValue exception) { this.exception = exception; - assert asRegister(exception) == EXCEPTION; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - // Copy the saved RBP value into the slot just below the return address - // so that the stub can pick it up from there. - AMD64Address rbpSlot; - int rbpSlotOffset = tasm.frameMap.frameSize() - 8; - if (isStackSlot(savedRbp)) { - rbpSlot = (AMD64Address) tasm.asAddress(savedRbp); - assert rbpSlot.getDisplacement() == rbpSlotOffset; - } else { - rbpSlot = new AMD64Address(rsp, rbpSlotOffset); - masm.movq(rbpSlot, asRegister(savedRbp)); - } + leaveFrameAndRestoreRbp(tasm, masm); - // Pass the address of the RBP slot in RBP itself - masm.leaq(rbp, rbpSlot); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION), AMD64.r10, false, null); + RuntimeCallTarget stub = tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION_TO_CALLER); + CallingConvention cc = stub.getCallingConvention(); + assert cc.getArgumentCount() == 2; + assert exception.equals(cc.getArgument(0)); + + // Get return address (is on top of stack after leave). + Register returnAddress = asRegister(cc.getArgument(1)); + masm.movq(returnAddress, new AMD64Address(rsp, 0)); + + AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupRuntimeCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER)); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Mon May 13 17:11:31 2013 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.sparc.*; import com.oracle.graal.hotspot.*; @@ -42,8 +43,14 @@ } @Override - public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - return new SPARCLIRGenerator(graph, this.runtime(), this.target, frameMap, method, lir); + public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, CallingConvention cc, LIR lir) { + return new SPARCLIRGenerator(graph, this.runtime(), this.target, frameMap, cc, lir); + } + + @Override + protected AbstractAssembler createAssembler(FrameMap frameMap) { + // SPARC: Create assembler. + return null; } @Override @@ -53,7 +60,7 @@ } @Override - public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { + public void emitCode(TargetMethodAssembler tasm, LIRGenerator lirGen, ResolvedJavaMethod codeCacheOwner) { // SPARC: Emit code } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon May 13 17:11:31 2013 +0200 @@ -22,12 +22,14 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.api.code.CodeUtil.*; import static com.oracle.graal.nodes.StructuredGraph.*; import java.lang.reflect.Modifier; import java.util.concurrent.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; @@ -157,8 +159,10 @@ graph = graph.copy(); } InliningUtil.InlinedBytecodes.add(method.getCodeSize()); - return GraalCompiler.compileMethod(graalRuntime.getRuntime(), replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan, - optimisticOpts, method.getSpeculationLog()); + HotSpotRuntime runtime = graalRuntime.getRuntime(); + CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); + return GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), graalRuntime.getCache(), plan, optimisticOpts, + method.getSpeculationLog()); } }); } finally { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon May 13 17:11:31 2013 +0200 @@ -22,15 +22,52 @@ */ package com.oracle.graal.hotspot; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.word.*; /** * HotSpot specific backend. */ public abstract class HotSpotBackend extends Backend { + /** + * Descriptor for SharedRuntime::deopt_blob()->uncommon_trap(). + */ + public static final Descriptor UNCOMMON_TRAP = new Descriptor("deoptimize", true, void.class); + + /** + * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the + * {@linkplain Marks#MARK_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled method. + */ + public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class, Object.class, Word.class); + + /** + * Descriptor for SharedRuntime::deopt_blob()->unpack(). + */ + public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class); + + /** + * Descriptor for SharedRuntime::get_ic_miss_stub(). + */ + public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class); + + /** + * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated + * from {@link UnwindNode}. + */ + public static final Descriptor UNWIND_EXCEPTION_TO_CALLER = new Descriptor("unwindExceptionToCaller", true, void.class, Object.class, Word.class); + + /** + * Descriptor for the arguments when unwinding to an exception handler in a caller. + */ + public static final Descriptor EXCEPTION_HANDLER_IN_CALLER = new Descriptor("exceptionHandlerInCaller", false, void.class, Object.class, Word.class); + public HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) { super(runtime, target); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Mon May 13 17:11:31 2013 +0200 @@ -22,11 +22,20 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CompilationResult.*; +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.DataPatch; +import com.oracle.graal.api.code.CompilationResult.ExceptionHandler; +import com.oracle.graal.api.code.CompilationResult.Infopoint; +import com.oracle.graal.api.code.CompilationResult.Mark; +import com.oracle.graal.api.code.CompilationResult.Site; +import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; /** * Augments a {@link CompilationResult} with HotSpot-specific information. @@ -35,27 +44,66 @@ private static final long serialVersionUID = 7807321392203253218L; public final CompilationResult comp; - public final HotSpotResolvedJavaMethod method; // used only for methods - public final int entryBCI; // used only for methods - public final String name; // used only for stubs + + /** + * Non-null for installation of an nmethod. + */ + public final HotSpotResolvedJavaMethod method; + public final int entryBCI; + + /** + * Non-null for installation of a RuntimeStub. + */ + public final String stubName; public final Site[] sites; public final ExceptionHandler[] exceptionHandlers; public HotSpotCompilationResult(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult comp) { this.method = method; + this.stubName = null; this.comp = comp; this.entryBCI = entryBCI; - this.name = null; sites = getSortedSites(comp); - if (comp.getExceptionHandlers() == null) { + if (comp.getExceptionHandlers().isEmpty()) { exceptionHandlers = null; } else { exceptionHandlers = comp.getExceptionHandlers().toArray(new ExceptionHandler[comp.getExceptionHandlers().size()]); } } + public HotSpotCompilationResult(Stub stub, CompilationResult comp) { + assert checkStubInvariants(comp); + this.method = null; + this.stubName = stub.toString(); + this.comp = comp; + this.entryBCI = 0; + + sites = getSortedSites(comp); + assert comp.getExceptionHandlers().isEmpty(); + exceptionHandlers = null; + } + + /** + * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub. + */ + private boolean checkStubInvariants(CompilationResult compResult) { + for (DataPatch data : compResult.getDataReferences()) { + Constant constant = data.constant; + assert constant.getKind() != Kind.Object : this + " cannot have embedded object constant: " + constant; + assert constant.getPrimitiveAnnotation() == null : this + " cannot have embedded metadata: " + constant; + } + for (Infopoint infopoint : compResult.getInfopoints()) { + assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint; + Call call = (Call) infopoint; + assert call.target instanceof HotSpotRuntimeCallTarget : this + " cannot have non runtime call: " + call.target; + HotSpotRuntimeCallTarget callTarget = (HotSpotRuntimeCallTarget) call.target; + assert callTarget.getAddress() == graalRuntime().getConfig().uncommonTrapStub || callTarget.isCRuntimeCall() : this + "must only call C runtime or deoptimization stub, not " + call.target; + } + return true; + } + static class SiteComparator implements Comparator { public int compare(Site s1, Site s2) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon May 13 17:11:31 2013 +0200 @@ -84,6 +84,15 @@ runtime.compilerToVm = toVM; } + protected static HotSpotGraalRuntimeFactory findFactory(String architecture) { + for (HotSpotGraalRuntimeFactory factory : ServiceLoader.loadInstalled(HotSpotGraalRuntimeFactory.class)) { + if (factory.getArchitecture().equals(architecture) && factory.getName().equals(GraalOptions.GraalRuntime)) { + return factory; + } + } + return null; + } + private static Kind wordKind; /** @@ -114,8 +123,9 @@ return unsafe.getInt(object, offset); } - protected/* final */CompilerToVM compilerToVm; - protected/* final */VMToCompiler vmToCompiler; + protected/* final */CompilerToVM compilerToVm; + protected/* final */CompilerToGPU compilerToGpu; + protected/* final */VMToCompiler vmToCompiler; protected final HotSpotRuntime runtime; protected final TargetDescription target; @@ -128,12 +138,14 @@ private final HotSpotBackend backend; protected HotSpotGraalRuntime() { - CompilerToVM toVM = new CompilerToVMImpl(); + CompilerToVM toVM = new CompilerToVMImpl(); + CompilerToGPU toGPU = new CompilerToGPUImpl(); // initialize VmToCompiler VMToCompiler toCompiler = new VMToCompilerImpl(this); - compilerToVm = toVM; + compilerToVm = toVM; + compilerToGpu = toGPU; vmToCompiler = toCompiler; config = new HotSpotVMConfig(); compilerToVm.initializeConfiguration(config); @@ -215,6 +227,10 @@ return vmToCompiler; } + public CompilerToGPU getCompilerToGPU() { + return compilerToGpu; + } + public JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve) { if (name.length() == 1 && vmToCompiler instanceof VMToCompilerImpl) { VMToCompilerImpl impl = (VMToCompilerImpl) vmToCompiler; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntimeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntimeFactory.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,32 @@ +/* + * 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.hotspot; + +public interface HotSpotGraalRuntimeFactory { + + HotSpotGraalRuntime createRuntime(); + + String getArchitecture(); + + String getName(); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; /** @@ -42,6 +43,12 @@ */ void emitTailcall(Value[] args, Value address); + void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason); + + void emitPatchReturnAddress(ValueNode address); + + void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc); + void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); /** diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Mon May 13 17:11:31 2013 +0200 @@ -36,6 +36,11 @@ public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget { /** + * Sentinel marker for a computed jump address. + */ + public static final long JUMP_ADDRESS = 0xDEADDEADBEEFBEEFL; + + /** * The descriptor of the stub. This is for informational purposes only. */ public final Descriptor descriptor; @@ -46,7 +51,7 @@ private long address; /** - * Non-null (eventually) iff this is a call to a snippet-based {@linkplain Stub stub}. + * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. */ private Stub stub; @@ -57,8 +62,11 @@ private final CompilerToVM vm; - public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, CallingConvention cc, CompilerToVM vm) { + private final boolean isCRuntimeCall; + + public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, boolean isCRuntimeCall, CallingConvention cc, CompilerToVM vm) { this.address = address; + this.isCRuntimeCall = isCRuntimeCall; this.descriptor = descriptor; this.cc = cc; this.vm = vm; @@ -66,7 +74,7 @@ @Override public String toString() { - return (stub == null ? descriptor.toString() : MetaUtil.format("%h.%n", stub.getMethod())) + "@0x" + Long.toHexString(address) + ":" + cc; + return (stub == null ? descriptor.toString() : stub) + "@0x" + Long.toHexString(address) + ":" + cc; } public CallingConvention getCallingConvention() { @@ -88,7 +96,7 @@ public void finalizeAddress(Backend backend) { if (address == 0) { - assert stub != null : "linkage without an address must be a stub"; + assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?"; InstalledCode code = stub.getCode(backend); AllocatableValue[] argumentLocations = new AllocatableValue[cc.getArgumentCount()]; @@ -96,10 +104,10 @@ argumentLocations[i] = cc.getArgument(i); } - Set definedRegisters = stub.getDefinedRegisters(); - AllocatableValue[] temporaryLocations = new AllocatableValue[definedRegisters.size()]; + Set destroyedRegisters = stub.getDestroyedRegisters(); + AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; int i = 0; - for (Register reg : definedRegisters) { + for (Register reg : destroyedRegisters) { temporaryLocations[i++] = reg.asValue(); } // Update calling convention with temporaries @@ -108,9 +116,30 @@ } } + public long getAddress() { + assert address != 0L : "address not yet finalized: " + this; + return address; + } + @Override - public boolean preservesRegisters() { - assert address != 0; - return true; + public boolean destroysRegisters() { + if (isCRuntimeCall) { + // Even though most native ABIs define some callee saved registers, + // for simplicity we force the register allocator to save all live + // registers across a C runtime call as such calls are only made from + // compiled stubs which a) are slow path and b) will typically only + // have very few live registers across a C runtime call + return true; + } + // This is a call to a compiled (or assembler) stub which saves + // all registers (apart from its temporaries) + return false; + } + + /** + * Determines if this is a link to a C/C++ function in the HotSpot runtime. + */ + public boolean isCRuntimeCall() { + return isCRuntimeCall; } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon May 13 17:11:31 2013 +0200 @@ -33,7 +33,8 @@ } // os information, register layout, code generation, ... - public boolean windowsOs; + public boolean cAssertions; + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); public int codeEntryAlignment; public boolean verifyOops; public boolean ciTime; @@ -136,6 +137,9 @@ */ public int threadTlabEndOffset; + /** + * The value of JavaThread::threadObj_offset(). + */ public int threadObjectOffset; /** @@ -179,6 +183,14 @@ public int uninitializedIdentityHashCodeValue; /** + * Offset of the _pending_exception field in ThreadShadow (defined in exceptions.hpp). This + * field is used to propagate exceptions through C/C++ calls. + *

    + * NOTE: This is not the same as {@link #threadExceptionOopOffset}. + */ + public int pendingExceptionOffset; + + /** * Offset of the pending deoptimization field. */ public int pendingDeoptimizationOffset; @@ -223,7 +235,24 @@ */ public int klassHasFinalizerFlag; + /** + * The value of JavaThread::is_method_handle_return_offset(). + */ + public int threadIsMethodHandleReturnOffset; + + public long verifyOopCounterAddress; + public long verifyOopMask; + public long verifyOopBits; + + /** + * Offset of the _exception_oop field in Thread (defined in thread.hpp). This field is used to + * pass exception objects into and out of the runtime system during exception handling for + * compiled code. + *

    + * NOTE: This is not the same as {@link #pendingExceptionOffset}. + */ public int threadExceptionOopOffset; + public int threadExceptionPcOffset; public long cardtableStartAddress; public int cardtableShift; @@ -302,6 +331,10 @@ public int threadTlabStartOffset; public int threadTlabSizeOffset; public int threadAllocatedBytesOffset; + public int threadLastJavaSpOffset; + public int threadLastJavaFpOffset; + public int threadLastJavaPcOffset; + public int threadObjectResultOffset; public int tlabRefillWasteLimitOffset; public int tlabRefillWasteIncrement; public int tlabAlignmentReserve; @@ -334,44 +367,43 @@ public int typeProfileWidth; // runtime stubs - public long newInstanceStub; - public long newArrayStub; - public long newMultiArrayStub; public long inlineCacheMissStub; - public long handleExceptionStub; public long handleDeoptStub; - public long monitorEnterStub; - public long monitorExitStub; - public long wbPreCallStub; - public long wbPostCallStub; - public long verifyOopStub; - public long vmErrorStub; - public long deoptimizeStub; + public long uncommonTrapStub; public long unwindExceptionStub; - public long osrMigrationEndStub; - public long registerFinalizerStub; - public long createNullPointerExceptionStub; - public long createOutOfBoundsExceptionStub; public long javaTimeMillisStub; public long javaTimeNanosStub; - public long arithmeticFremStub; - public long arithmeticDremStub; public long arithmeticSinStub; public long arithmeticCosStub; public long arithmeticTanStub; - public long logPrimitiveStub; - public long logObjectStub; - public long logPrintfStub; - public long stubPrintfStub; public int deoptReasonNone; - public long threadIsInterruptedStub; - public long identityHashCodeStub; public long aescryptEncryptBlockStub; public long aescryptDecryptBlockStub; public long cipherBlockChainingEncryptAESCryptStub; public long cipherBlockChainingDecryptAESCryptStub; + public long newInstanceAddress; + public long newArrayAddress; + public long newMultiArrayAddress; + public long registerFinalizerAddress; + public long threadIsInterruptedAddress; + public long vmMessageAddress; + public long identityHashCodeAddress; + public long exceptionHandlerForPcAddress; + public long exceptionHandlerForReturnAddressAddress; + public long osrMigrationEndAddress; + public long monitorenterAddress; + public long monitorexitAddress; + public long createNullPointerExceptionAddress; + public long createOutOfBoundsExceptionAddress; + public long logPrimitiveAddress; + public long logObjectAddress; + public long logPrintfAddress; + public long vmErrorAddress; + public long writeBarrierPreAddress; + public long writeBarrierPostAddress; + public int deoptReasonNullCheck; public int deoptReasonRangeCheck; public int deoptReasonClassCheck; @@ -384,6 +416,7 @@ public int deoptReasonJsrMismatch; public int deoptReasonDiv0Check; public int deoptReasonConstraint; + public int deoptReasonLoopLimitCheck; public int deoptActionNone; public int deoptActionMaybeRecompile; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPU.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,55 @@ +/* + * 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.hotspot.bridge; + +import com.oracle.graal.api.code.InvalidInstalledCodeException; + +/** + * Calls from Java into the GPU. + */ +public interface CompilerToGPU { + + /** + * Attempts to initialize and create a valid context with the GPU. + * + * @return whether the GPU context has been initialized and is valid. + */ + boolean deviceInit(); + + /** + * Attempts to detach from a valid GPU context. + * + * @return whether the GPU context has been properly disposed. + */ + boolean deviceDetach(); + + /** + * Attempts to generate and return a bound function to the + * loaded method kernel on the GPU. + * + * @param code the text or binary values for a method kernel + * @return the value of the bound kernel in GPU space. + */ + long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException; +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToGPUImpl.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,40 @@ +/* + * 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.bridge; + +import com.oracle.graal.api.code.InvalidInstalledCodeException; + + +/** + * Entries into the HotSpot GPU interface from Java code. + */ +public class CompilerToGPUImpl implements CompilerToGPU { + + public native boolean deviceInit(); + + public native long generateKernel(byte[] code, String name) throws InvalidInstalledCodeException; + + public native boolean deviceDetach(); + +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon May 13 17:11:31 2013 +0200 @@ -151,8 +151,7 @@ * Installs the result of a compilation into the code cache. * * @param compResult the result of a compilation - * @param code if not null, then the code is installed as the non-default compiled code for the - * associated method and the details of the installation are written to this object + * @param code the details of the installed CodeBlob are written to this object * @return the outcome of the installation as a {@link CodeInstallResult}. */ CodeInstallResult installCode(HotSpotCompilationResult compResult, HotSpotInstalledCode code, SpeculationLog cache); @@ -192,25 +191,27 @@ HotSpotResolvedJavaField getJavaField(Field reflectionField); - long getMaxCallTargetOffset(long stub); + long getMaxCallTargetOffset(long address); - String disassembleNMethod(long nmethod); + String disassembleCodeBlob(long codeBlob); /** - * Gets a copy of the machine code for an nmethod. + * Gets a copy of the machine code for a CodeBlob. * - * @return the machine code for {@code nmethod} if it is valid, null otherwise + * @return the machine code for {@code codeBlob} if it is valid, null otherwise */ - byte[] getCode(long nmethod); + byte[] getCode(long codeBlob); StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); - Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException; + Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException; - Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException; + Object executeCompiledMethodVarargs(Object[] args, long nmethod) throws InvalidInstalledCodeException; int getVtableEntryOffset(long metaspaceMethod); + boolean hasVtableEntry(long metaspaceMethod); + long[] getDeoptedLeafGraphIds(); long[] getLineNumberTable(HotSpotResolvedJavaMethod method); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon May 13 17:11:31 2013 +0200 @@ -127,24 +127,27 @@ public native int getCompiledCodeSize(long metaspaceMethod); @Override - public native long getMaxCallTargetOffset(long stub); + public native long getMaxCallTargetOffset(long address); @Override - public native String disassembleNMethod(long nmethod); + public native String disassembleCodeBlob(long codeBlob); @Override - public native byte[] getCode(long nmethod); + public native byte[] getCode(long codeBlob); @Override public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @Override - public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod); + public native Object executeCompiledMethodVarargs(Object[] args, long nmethod); @Override public native int getVtableEntryOffset(long metaspaceMethod); @Override + public native boolean hasVtableEntry(long metaspaceMethod); + + @Override public native long[] getDeoptedLeafGraphIds(); @Override @@ -172,16 +175,16 @@ public native boolean isInstalledCodeValid(long nativeMethod); @Override - public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException { - return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod); + public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nmethod) throws InvalidInstalledCodeException { + return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nmethod); } /** - * Direct call to the given nativeMethod with three object arguments and an object return value. - * This method does not have an implementation on the C++ side, but its entry points (from + * Direct call to the given nmethod with three object arguments and an object return value. This + * method does not have an implementation on the C++ side, but its entry points (from * interpreter and from compiled code) are directly pointing to a manually generated assembly * stub that does the necessary argument shuffling and a tail call via an indirect jump to the * verified entry point of the given native method. */ - private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod); + private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nmethod); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Mon May 13 17:11:31 2013 +0200 @@ -30,34 +30,49 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.stubs.*; /** - * Implementation of {@link InstalledCode} for HotSpot. Stores a reference to the nmethod which - * contains the compiled code. The nmethod also stores a weak reference to the HotSpotCompiledMethod - * instance which is necessary to keep the nmethod from being unloaded. + * Implementation of {@link InstalledCode} for HotSpot. If the code is installed as an nmethod (as + * opposed to some other subclass of CodeBlob such as RuntimeStub), then the nmethod stores a weak + * reference to an instance of this class. This is necessary to keep the nmethod from being unloaded + * while the associated {@link HotSpotInstalledCode} instance is alive. + *

    + * Note that there is no (current) way for the reference from an nmethod to a + * {@link HotSpotInstalledCode} instance to be anything but weak. This is due to the fact that + * HotSpot does not treat nmethods as strong GC roots. */ public class HotSpotInstalledCode extends CompilerObject implements InstalledCode { private static final long serialVersionUID = 156632908220561612L; private final HotSpotResolvedJavaMethod method; + private final Stub stub; private final boolean isDefault; private final Graph graph; - long nmethod; + long codeBlob; long start; public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, Graph graph, boolean isDefault) { this.method = method; + this.stub = null; this.graph = graph; this.isDefault = isDefault; } + public HotSpotInstalledCode(Stub stub) { + this.method = null; + this.stub = stub; + this.graph = null; + this.isDefault = false; + } + public boolean isDefault() { return isDefault; } - public long getMethodAddress() { - return nmethod; + public long getCodeBlob() { + return codeBlob; } public Graph getGraph() { @@ -71,26 +86,32 @@ @Override public boolean isValid() { - return graalRuntime().getCompilerToVM().isInstalledCodeValid(nmethod); + return stub != null || graalRuntime().getCompilerToVM().isInstalledCodeValid(codeBlob); } @Override public void invalidate() { - graalRuntime().getCompilerToVM().invalidateInstalledCode(nmethod); + if (stub == null) { + graalRuntime().getCompilerToVM().invalidateInstalledCode(codeBlob); + } } @Override public String toString() { - return String.format("InstalledCode[method=%s, nmethod=0x%x]", method, nmethod); + if (stub != null) { + return String.format("InstalledCode[stub=%s, codeBlob=0x%x]", stub, codeBlob); + } + return String.format("InstalledCode[method=%s, codeBlob=0x%x, isDefault=%b]", method, codeBlob, isDefault); } @Override public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { + assert stub == null; assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3; assert method.getSignature().getParameterKind(0) == Kind.Object; assert method.getSignature().getParameterKind(1) == Kind.Object; assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object; - return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod); + return graalRuntime().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, codeBlob); } private boolean checkArgs(Object... args) { @@ -109,8 +130,9 @@ @Override public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + assert stub == null; assert checkArgs(args); - return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod); + return graalRuntime().getCompilerToVM().executeCompiledMethodVarargs(args, codeBlob); } @Override @@ -120,6 +142,6 @@ @Override public byte[] getCode() { - return graalRuntime().getCompilerToVM().getCode(nmethod); + return graalRuntime().getCompilerToVM().getCode(codeBlob); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java Mon May 13 17:11:31 2013 +0200 @@ -63,4 +63,23 @@ public String toString() { return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]"; } + + @Override + public int hashCode() { + final int prime = 43; + int result = super.hashCode(); + result = prime * result + (eliminated ? 1231 : 1237); + result = prime * result + owner.hashCode(); + result = prime * result + slot.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotMonitorValue) { + HotSpotMonitorValue other = (HotSpotMonitorValue) obj; + return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot); + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Mon May 13 17:11:31 2013 +0200 @@ -31,13 +31,14 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; /** * Represents a field in a HotSpot type. */ -public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField { +public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField, LocationIdentity { // Must not conflict with any fields flags used by the VM - the assertion in the constructor // checks this assumption diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon May 13 17:11:31 2013 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.phases.*; @@ -53,6 +54,10 @@ private final HotSpotResolvedObjectType holder; private/* final */int codeSize; private/* final */int exceptionHandlerCount; + private boolean callerSensitive; + private boolean forceInline; + private boolean dontInline; + private boolean ignoredBySecurityStackWalk; private HotSpotSignature signature; private Boolean hasBalancedMonitors; private Map compilerStorage; @@ -84,6 +89,11 @@ } @Override + public Constant getEncoding() { + return getMetaspaceMethodConstant(); + } + + @Override public int getModifiers() { HotSpotVMConfig config = graalRuntime().getConfig(); return unsafe.getInt(metaspaceMethod + config.methodAccessFlagsOffset) & Modifier.methodModifiers(); @@ -124,6 +134,43 @@ return graalRuntime().getCompilerToVM().initializeExceptionHandlers(metaspaceMethod, handlers); } + /** + * Returns true if this method has a CallerSensitive annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + public boolean isCallerSensitive() { + return callerSensitive; + } + + /** + * Returns true if this method has a ForceInline annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return forceInline; + } + + /** + * Returns true if this method has a DontInline annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return dontInline; + } + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + public boolean ignoredBySecurityStackWalk() { + return ignoredBySecurityStackWalk; + } + public boolean hasBalancedMonitors() { if (hasBalancedMonitors == null) { hasBalancedMonitors = graalRuntime().getCompilerToVM().hasBalancedMonitors(metaspaceMethod); @@ -318,18 +365,23 @@ } /** - * Returns the offset of this method into the v-table. If the holder is not initialized, returns - * -1 + * Returns the offset of this method into the v-table. The method must have a v-table entry has + * indicated by {@link #isInVirtualMethodTable()}, otherwise an exception is thrown. * * @return the offset of this method into the v-table */ public int vtableEntryOffset() { - if (!holder.isInitialized()) { - return -1; + if (!isInVirtualMethodTable() || !holder.isInitialized()) { + throw new GraalInternalError("%s does not have a vtable entry", this); } return graalRuntime().getCompilerToVM().getVtableEntryOffset(metaspaceMethod); } + @Override + public boolean isInVirtualMethodTable() { + return graalRuntime().getCompilerToVM().hasVtableEntry(metaspaceMethod); + } + public void setCurrentTask(CompilationTask task) { currentTask = task; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon May 13 17:11:31 2013 +0200 @@ -25,14 +25,42 @@ import static com.oracle.graal.api.code.CallingConvention.Type.*; import static com.oracle.graal.api.code.DeoptimizationAction.*; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.code.Register.RegisterFlag.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.hotspot.HotSpotBackend.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; +import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; +import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*; +import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; +import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; +import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*; +import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*; +import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.IDENTITY_HASHCODE; import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; +import static com.oracle.graal.hotspot.stubs.CreateNullPointerExceptionStub.*; +import static com.oracle.graal.hotspot.stubs.CreateOutOfBoundsExceptionStub.*; +import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*; +import static com.oracle.graal.hotspot.stubs.LogObjectStub.*; +import static com.oracle.graal.hotspot.stubs.LogPrimitiveStub.*; +import static com.oracle.graal.hotspot.stubs.LogPrintfStub.*; +import static com.oracle.graal.hotspot.stubs.MonitorEnterStub.*; +import static com.oracle.graal.hotspot.stubs.MonitorExitStub.*; +import static com.oracle.graal.hotspot.stubs.NewArrayStub.*; +import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; +import static com.oracle.graal.hotspot.stubs.NewMultiArrayStub.*; +import static com.oracle.graal.hotspot.stubs.OSRMigrationEndStub.*; +import static com.oracle.graal.hotspot.stubs.RegisterFinalizerStub.*; +import static com.oracle.graal.hotspot.stubs.StubUtil.*; +import static com.oracle.graal.hotspot.stubs.ThreadIsInterruptedStub.*; +import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*; +import static com.oracle.graal.hotspot.stubs.VMErrorStub.*; +import static com.oracle.graal.hotspot.stubs.WriteBarrierPostStub.*; +import static com.oracle.graal.hotspot.stubs.WriteBarrierPreStub.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.replacements.Log.*; @@ -49,7 +77,6 @@ import com.oracle.graal.api.code.CompilationResult.DataPatch; import com.oracle.graal.api.code.CompilationResult.Infopoint; import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -57,7 +84,6 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.java.*; @@ -69,6 +95,7 @@ import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.printer.*; import com.oracle.graal.replacements.*; @@ -79,6 +106,8 @@ */ public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider { + public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class); + public final HotSpotVMConfig config; protected final RegisterConfig regConfig; @@ -94,14 +123,6 @@ private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; private final Map runtimeCalls = new HashMap<>(); - private final Map stubs = new HashMap<>(); - - /** - * Holds onto objects that will be embedded in compiled code. HotSpot treats oops embedded in - * code as weak references so without an external strong root, such an embedded oop will quickly - * die. This in turn will cause the nmethod to be unloaded. - */ - private final Map gcRoots = new HashMap<>(); /** * The offset from the origin of an array to the first element. @@ -185,13 +206,12 @@ int currentStackOffset = 0; for (int i = 0; i < arguments.length; i++) { Kind kind = arguments[i]; - RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU; - Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, flag); + Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, kind); if (i < ccRegs.length) { result[i] = ccRegs[i].asValue(kind); } else { result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false); - currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize); + currentStackOffset += Math.max(target.arch.getSizeInBytes(kind), target.wordSize); } } return result; @@ -202,27 +222,80 @@ this.graalRuntime = graalRuntime; regConfig = createRegisterConfig(false); globalStubRegConfig = createRegisterConfig(true); + Kind word = graalRuntime.getTarget().wordKind; // @formatter:off - addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, - /* temps */ null, + addStubCall(VERIFY_OOP, + /* ret */ ret(Kind.Object), + /* arg0: object */ javaCallingConvention(Kind.Object)); + + addStubCall(OSR_MIGRATION_END, + /* ret */ ret(Kind.Void), + /* arg0: buffer */ javaCallingConvention(word)); + + addCRuntimeCall(OSR_MIGRATION_END_C, config.osrMigrationEndAddress, /* ret */ ret(Kind.Void), - /* arg0: long */ javaCallingConvention(Kind.Long)); + /* arg0: buffer */ nativeCallingConvention(word)); + + addRuntimeCall(UNCOMMON_TRAP, config.uncommonTrapStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); + + addCRuntimeCall(EXCEPTION_HANDLER_FOR_PC, config.exceptionHandlerForPcAddress, + /* ret */ ret(word), + /* arg0: thread */ nativeCallingConvention(word)); - addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub, - /* temps */ null, + addStubCall(UNWIND_EXCEPTION_TO_CALLER, + /* ret */ ret(Kind.Void), + /* arg0: exception */ javaCallingConvention(Kind.Object, + /* arg1: returnAddress */ word)); + + addCRuntimeCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, config.exceptionHandlerForReturnAddressAddress, + /* ret */ ret(word), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: returnAddress */ word)); + addStubCall(REGISTER_FINALIZER, /* ret */ ret(Kind.Void), /* arg0: object */ javaCallingConvention(Kind.Object)); - addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Object)); + addCRuntimeCall(REGISTER_FINALIZER_C, config.registerFinalizerAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object)); + + addStubCall(NEW_ARRAY, + /* ret */ ret(Kind.Object), + /* arg0: hub */ javaCallingConvention(word, + /* arg1: length */ Kind.Int)); + + addCRuntimeCall(NEW_ARRAY_C, config.newArrayAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word, + /* arg2: length */ Kind.Int)); - addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub, - /* temps */ null, + addStubCall(NEW_INSTANCE, + /* ret */ ret(Kind.Object), + /* arg0: hub */ javaCallingConvention(word)); + + addCRuntimeCall(NEW_INSTANCE_C, config.newInstanceAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word)); + + addStubCall(NEW_MULTI_ARRAY, /* ret */ ret(Kind.Object), - /* arg0: index */ javaCallingConvention(Kind.Int)); + /* arg0: hub */ javaCallingConvention(word, + /* arg1: rank */ Kind.Int, + /* arg2: dims */ word)); + + addCRuntimeCall(NEW_MULTI_ARRAY_C, config.newMultiArrayAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: hub */ word, + /* arg2: rank */ Kind.Int, + /* arg3: dims */ word)); addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, /* temps */ this.regConfig.getCallerSaveRegisters(), @@ -247,34 +320,142 @@ /* ret */ ret(Kind.Double), /* arg0: index */ javaCallingConvention(Kind.Double)); - addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub, - /* temps */ null, + addStubCall(LOG_PRIMITIVE, /* ret */ ret(Kind.Void), /* arg0: typeChar */ javaCallingConvention(Kind.Int, /* arg1: value */ Kind.Long, /* arg2: newline */ Kind.Boolean)); - addRuntimeCall(LOG_PRINTF, config.logPrintfStub, - /* temps */ null, + addCRuntimeCall(LOG_PRIMITIVE_C, config.logPrimitiveAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: typeChar */ Kind.Char, + /* arg2: value */ Kind.Long, + /* arg3: newline */ Kind.Boolean)); + + addStubCall(LOG_PRINTF, /* ret */ ret(Kind.Void), /* arg0: format */ javaCallingConvention(Kind.Object, /* arg1: value */ Kind.Long, /* arg2: value */ Kind.Long, /* arg3: value */ Kind.Long)); - addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub, - /* temps */ null, + addCRuntimeCall(LOG_PRINTF_C, config.logObjectAddress, /* ret */ ret(Kind.Void), - /* arg0: format */ javaCallingConvention(Kind.Long, - /* arg1: value */ Kind.Long, - /* arg2: value */ Kind.Long, - /* arg3: value */ Kind.Long)); + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: format */ Kind.Object, + /* arg2: v1 */ Kind.Long, + /* arg3: v2 */ Kind.Long, + /* arg4: v3 */ Kind.Long)); - addRuntimeCall(LOG_OBJECT, config.logObjectStub, - /* temps */ null, + addCRuntimeCall(VM_MESSAGE_C, config.vmMessageAddress, + /* ret */ ret(Kind.Void), + /* arg0: vmError */ nativeCallingConvention(Kind.Boolean, + /* arg1: format */ word, + /* arg2: value */ Kind.Long, + /* arg3: value */ Kind.Long, + /* arg4: value */ Kind.Long)); + + addStubCall(LOG_OBJECT, /* ret */ ret(Kind.Void), /* arg0: object */ javaCallingConvention(Kind.Object, /* arg1: flags */ Kind.Int)); + + addCRuntimeCall(LOG_OBJECT_C, config.logObjectAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object, + /* arg2: flags */ Kind.Int)); + + addStubCall(THREAD_IS_INTERRUPTED, + /* ret */ ret(Kind.Boolean), + /* arg0: thread */ javaCallingConvention(Kind.Object, + /* arg1: clearInterrupted */ Kind.Boolean)); + + addCRuntimeCall(THREAD_IS_INTERRUPTED_C, config.threadIsInterruptedAddress, + /* ret */ ret(Kind.Boolean), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: receiverThread */ Kind.Object, + /* arg1: clearInterrupted */ Kind.Boolean)); + + addRuntimeCall(DEOPT_HANDLER, config.handleDeoptStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); + + addRuntimeCall(IC_MISS_HANDLER, config.inlineCacheMissStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); + + addStubCall(MONITORENTER, + /* ret */ ret(Kind.Void), + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: lock */ word)); + + addCRuntimeCall(MONITORENTER_C, config.monitorenterAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object, + /* arg1: lock */ word)); + + addStubCall(MONITOREXIT, + /* ret */ ret(Kind.Void), + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: lock */ word)); + + addCRuntimeCall(MONITOREXIT_C, config.monitorexitAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object, + /* arg1: lock */ word)); + + addStubCall(CREATE_NULL_POINTER_EXCEPTION, + /* ret */ ret(Kind.Object)); + + addCRuntimeCall(CREATE_NULL_POINTER_EXCEPTION_C, config.createNullPointerExceptionAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word)); + + addStubCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, + /* ret */ ret(Kind.Object), + /* arg0: index */ javaCallingConvention(Kind.Int)); + + addCRuntimeCall(CREATE_OUT_OF_BOUNDS_C, config.createOutOfBoundsExceptionAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: index */ Kind.Int)); + + addStubCall(VM_ERROR, + /* ret */ ret(Kind.Void), + /* arg0: where */ javaCallingConvention(Kind.Object, + /* arg1: format */ Kind.Object, + /* arg2: value */ Kind.Long)); + + addCRuntimeCall(VM_ERROR_C, config.vmErrorAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg0: where */ Kind.Object, + /* arg1: format */ Kind.Object, + /* arg2: value */ Kind.Long)); + + addStubCall(WRITE_BARRIER_PRE, + /* ret */ ret(Kind.Void), + /* arg0: object */ javaCallingConvention(Kind.Object)); + + addCRuntimeCall(WRITE_BARRIER_PRE_C, config.writeBarrierPreAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object)); + + addStubCall(WRITE_BARRIER_POST, + /* ret */ ret(Kind.Void), + /* arg0: object */ javaCallingConvention(Kind.Object, + /* arg1: card */ word)); + + addCRuntimeCall(WRITE_BARRIER_POST_C, config.writeBarrierPostAddress, + /* ret */ ret(Kind.Void), + /* arg0: thread */ nativeCallingConvention(word, + /* arg1: object */ Kind.Object, + /* arg2: card */ word)); // @formatter:on } @@ -290,6 +471,33 @@ } /** + * Registers the details for a jump to a target that has a signature (i.e. expects arguments in + * specified locations). + * + * @param descriptor name and signature of the jump target + * @param args where arguments are passed to the call + */ + protected RuntimeCallTarget addJump(Descriptor descriptor, AllocatableValue... args) { + return addRuntimeCall(descriptor, HotSpotRuntimeCallTarget.JUMP_ADDRESS, null, ret(Kind.Void), args); + } + + /** + * Registers the details for a call to a runtime C/C++ function. + * + * @param descriptor name and signature of the call + * @param args where arguments are passed to the call + */ + protected RuntimeCallTarget addCRuntimeCall(Descriptor descriptor, long address, AllocatableValue ret, AllocatableValue... args) { + assert descriptor.getResultType().isPrimitive() || Word.class.isAssignableFrom(descriptor.getResultType()) : "C runtime call cannot have Object return type - objects must be returned via thread local storage: " + + descriptor; + return addRuntimeCall(descriptor, address, true, null, ret, args); + } + + protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) { + return addRuntimeCall(descriptor, address, false, tempRegs, ret, args); + } + + /** * Registers the details for linking a runtime call. * * @param descriptor name and signature of the call @@ -298,7 +506,7 @@ * @param ret where the call returns its result * @param args where arguments are passed to the call */ - protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) { + protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, boolean isCRuntimeCall, Register[] tempRegs, AllocatableValue ret, AllocatableValue... args) { AllocatableValue[] temps = tempRegs == null || tempRegs.length == 0 ? AllocatableValue.NONE : new AllocatableValue[tempRegs.length]; for (int i = 0; i < temps.length; i++) { temps[i] = tempRegs[i].asValue(); @@ -309,7 +517,7 @@ for (int i = 0; i < argTypes.length; i++) { assert checkAssignable(argTypes[i], args[i]) : descriptor + " incompatible with argument location " + i + ": " + args[i]; } - HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); + HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, isCRuntimeCall, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); runtimeCalls.put(descriptor, runtimeCall); return runtimeCall; } @@ -347,6 +555,9 @@ replacements.registerSubstitutions(AESCryptSubstitutions.class); replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class); } + if (GraalOptions.IntrinsifyReflectionMethods) { + replacements.registerSubstitutions(ReflectionSubstitutions.class); + } checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget()); instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget()); @@ -356,13 +567,40 @@ boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget()); exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget()); - registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); - registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); + link(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); + link(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); + link(new NewMultiArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_MULTI_ARRAY))); + link(new RegisterFinalizerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(REGISTER_FINALIZER))); + link(new ThreadIsInterruptedStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(THREAD_IS_INTERRUPTED))); + link(new ExceptionHandlerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(EXCEPTION_HANDLER))); + link(new UnwindExceptionToCallerStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(UNWIND_EXCEPTION_TO_CALLER))); + link(new VerifyOopStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VERIFY_OOP))); + link(new OSRMigrationEndStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(OSR_MIGRATION_END))); + link(new MonitorEnterStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(MONITORENTER))); + link(new MonitorExitStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(MONITOREXIT))); + link(new CreateNullPointerExceptionStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(CREATE_NULL_POINTER_EXCEPTION))); + link(new CreateOutOfBoundsExceptionStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(CREATE_OUT_OF_BOUNDS_EXCEPTION))); + link(new LogPrimitiveStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRIMITIVE))); + link(new LogObjectStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_OBJECT))); + link(new LogPrintfStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(LOG_PRINTF))); + link(new VMErrorStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(VM_ERROR))); + link(new WriteBarrierPreStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(WRITE_BARRIER_PRE))); + link(new WriteBarrierPostStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(WRITE_BARRIER_POST))); + + CompilerToVM c2vm = graalRuntime.getCompilerToVM(); + link(new RuntimeCallStub(config.identityHashCodeAddress, IDENTITY_HASHCODE, true, this, replacements, globalStubRegConfig, c2vm)); } - private void registerStub(Stub stub) { + private static void link(Stub stub) { stub.getLinkage().setStub(stub); - stubs.put(stub.getMethod(), stub); + } + + private void link(RuntimeCallStub stub) { + HotSpotRuntimeCallTarget linkage = stub.getLinkage(); + HotSpotRuntimeCallTarget targetLinkage = stub.getTargetLinkage(); + linkage.setStub(stub); + runtimeCalls.put(linkage.getDescriptor(), linkage); + runtimeCalls.put(targetLinkage.getDescriptor(), targetLinkage); } public HotSpotGraalRuntime getGraalRuntime() { @@ -516,7 +754,7 @@ ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; ValueNode array = arrayLengthNode.array(); ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt())); - arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array)); + tool.createNullCheckGuard(arrayLengthRead, array); graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); } else if (n instanceof Invoke) { Invoke invoke = (Invoke) n; @@ -525,7 +763,7 @@ NodeInputList parameters = callTarget.arguments(); ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { - invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver)); + tool.createNullCheckGuard(invoke, receiver); } JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); @@ -534,15 +772,14 @@ HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); if (!hsMethod.getDeclaringClass().isInterface()) { - int vtableEntryOffset = hsMethod.vtableEntryOffset(); - if (vtableEntryOffset > 0) { - // We use LocationNode.ANY_LOCATION for the reads that access the vtable - // entry and the compiled code entry - // as HotSpot does not guarantee they are final values. + if (hsMethod.isInVirtualMethodTable()) { + int vtableEntryOffset = hsMethod.vtableEntryOffset(); assert vtableEntryOffset > 0; - LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); - ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), - StampFactory.forKind(wordKind()))); + ReadNode hub = this.createReadHub(tool, graph, wordKind, receiver); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod); + // We use LocationNode.ANY_LOCATION for the reads that access the + // compiled code entry as HotSpot does not guarantee they are final + // values. ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), StampFactory.forKind(wordKind()))); @@ -567,8 +804,8 @@ HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); assert loadField.kind() != Kind.Illegal; - ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp())); - memoryRead.dependencies().add(tool.createNullCheckGuard(object)); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp())); + tool.createNullCheckGuard(memoryRead, object); graph.replaceFixedWithFixed(loadField, memoryRead); @@ -582,10 +819,9 @@ StoreFieldNode storeField = (StoreFieldNode) n; HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object(); - LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); WriteBarrierType barrierType = getFieldStoreBarrierType(storeField); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType)); - memoryWrite.dependencies().add(tool.createNullCheckGuard(object)); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType)); + tool.createNullCheckGuard(memoryWrite, object); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); FixedWithNextNode last = memoryWrite; @@ -605,15 +841,15 @@ cas.setWriteBarrierType(getCompareAndSwapBarrier(cas)); } else if (n instanceof LoadIndexedNode) { LoadIndexedNode loadIndexed = (LoadIndexedNode) n; - ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool); + GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); Kind elementKind = loadIndexed.elementKind(); LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp())); - memoryRead.dependencies().add(boundsCheck); + memoryRead.setGuard(boundsCheck); graph.replaceFixedWithFixed(loadIndexed, memoryRead); } else if (n instanceof StoreIndexedNode) { StoreIndexedNode storeIndexed = (StoreIndexedNode) n; - ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool); + GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool); Kind elementKind = storeIndexed.elementKind(); LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index()); ValueNode value = storeIndexed.value(); @@ -624,7 +860,7 @@ if (arrayType != null && array.objectStamp().isExactType()) { ResolvedJavaType elementType = arrayType.getComponentType(); if (!MetaUtil.isJavaLangObject(elementType)) { - CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null)); + CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null, true)); graph.addBeforeFixed(storeIndexed, checkcast); value = checkcast; } @@ -632,7 +868,7 @@ LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind)); LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind()))); - CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value)); + CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true)); graph.addBeforeFixed(storeIndexed, checkcast); graph.addBeforeFixed(checkcast, arrayClass); value = checkcast; @@ -640,7 +876,7 @@ } WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed); WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType)); - memoryWrite.dependencies().add(boundsCheck); + memoryWrite.setGuard(boundsCheck); memoryWrite.setStateAfter(storeIndexed.stateAfter()); graph.replaceFixedWithFixed(storeIndexed, memoryWrite); @@ -651,7 +887,7 @@ ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); // An unsafe read must not floating outside its block as may float above an explicit // null check on its object. - memoryRead.dependencies().add(BeginNode.prevBegin(load)); + memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); graph.replaceFixedWithFixed(load, memoryRead); } else if (n instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) n; @@ -661,23 +897,111 @@ WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); - } else if (n instanceof LoadHubNode) { LoadHubNode loadHub = (LoadHubNode) n; assert loadHub.kind() == wordKind; - LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); ValueNode object = loadHub.object(); - assert !object.isConstant() || object.asConstant().isNull(); - ValueNode guard = tool.createNullCheckGuard(object); - ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); - hub.dependencies().add(guard); + ReadNode hub = createReadHub(tool, graph, wordKind, object); graph.replaceFixed(loadHub, hub); + } else if (n instanceof LoadMethodNode) { + LoadMethodNode loadMethodNode = (LoadMethodNode) n; + ResolvedJavaMethod method = loadMethodNode.getMethod(); + ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); + graph.replaceFixed(loadMethodNode, metaspaceMethod); } else if (n instanceof FixedGuardNode) { FixedGuardNode node = (FixedGuardNode) n; - ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()))); + ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()).asNode())); graph.replaceFixedWithFixed(node, newAnchor); + } else if (n instanceof CommitAllocationNode) { + CommitAllocationNode commit = (CommitAllocationNode) n; + + ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()]; + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + + FixedWithNextNode newObject; + if (virtual instanceof VirtualInstanceNode) { + newObject = graph.add(new NewInstanceNode(virtual.type(), true)); + } else { + ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType(); + newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true)); + } + graph.addBeforeFixed(commit, newObject); + allocations[objIndex] = newObject; + } + int valuePos = 0; + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); + int entryCount = virtual.entryCount(); + + ValueNode newObject = allocations[objIndex]; + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos++); + if (value instanceof VirtualObjectNode) { + value = allocations[commit.getVirtualObjects().indexOf(value)]; + } + graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE))); + } + } else { + VirtualArrayNode array = (VirtualArrayNode) virtual; + ResolvedJavaType element = array.componentType(); + for (int i = 0; i < entryCount; i++) { + ValueNode value = commit.getValues().get(valuePos++); + if (value instanceof VirtualObjectNode) { + int indexOf = commit.getVirtualObjects().indexOf(value); + assert indexOf != -1 : commit + " " + value; + value = allocations[indexOf]; + } + graph.addBeforeFixed(commit, graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE))); + } + } + } + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex])); + allocations[objIndex] = anchor; + graph.addBeforeFixed(commit, anchor); + } + for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { + for (int lockDepth : commit.getLocks().get(objIndex)) { + MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth)); + graph.addBeforeFixed(commit, enter); + } + } + for (Node usage : commit.usages().snapshot()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject()); + graph.replaceFloating(addObject, allocations[index]); + } + graph.removeFixed(commit); } else if (n instanceof CheckCastNode) { checkcastSnippets.lower((CheckCastNode) n, tool); + } else if (n instanceof OSRStartNode) { + OSRStartNode osrStart = (OSRStartNode) n; + StartNode newStart = graph.add(new StartNode()); + LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind()))); + RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer)); + migrationEnd.setStateAfter(osrStart.stateAfter()); + + newStart.setNext(migrationEnd); + FixedNode next = osrStart.next(); + osrStart.setNext(null); + migrationEnd.setNext(next); + graph.setStart(newStart); + + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) + int localsOffset = (graph.method().getMaxLocals() - 1) * 8; + for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { + int size = FrameStateBuilder.stackSlots(osrLocal.kind()); + int offset = localsOffset - (osrLocal.index() + size - 1) * 8; + UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), osrLocal.kind())); + osrLocal.replaceAndDelete(load); + graph.addBeforeFixed(migrationEnd, load); + } + osrStart.replaceAtUsages(newStart); + osrStart.safeDelete(); } else if (n instanceof CheckCastDynamicNode) { checkcastSnippets.lower((CheckCastDynamicNode) n); } else if (n instanceof InstanceOfNode) { @@ -721,6 +1045,27 @@ } } + private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + assert !hsMethod.getDeclaringClass().isInterface(); + assert hsMethod.isInVirtualMethodTable(); + + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + assert vtableEntryOffset > 0; + // We use LocationNode.ANY_LOCATION for the reads that access the vtable + // entry as HotSpot does not guarantee that this is a final value. + ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind()))); + return metaspaceMethod; + } + + private ReadNode createReadHub(LoweringTool tool, StructuredGraph graph, Kind wordKind, ValueNode object) { + LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); + assert !object.isConstant() || object.asConstant().isNull(); + ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); + tool.createNullCheckGuard(hub, object); + return hub; + } + private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) { WriteBarrierType barrierType = WriteBarrierType.NONE; if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) { @@ -763,15 +1108,19 @@ return barrierType; } - private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { - int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind); + protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) { + return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); + } + + protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { + int scale = this.graalRuntime.getTarget().arch.getSizeInBytes(elementKind); return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); } - private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) n.graph(); + private static GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { + StructuredGraph graph = n.graph(); ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); - ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); + GuardingNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); graph.addBeforeFixed(n, arrayLength); return guard; @@ -781,16 +1130,6 @@ return HotSpotResolvedObjectType.fromClass(clazz); } - /** - * Gets the stub corresponding to a given method. - * - * @return the stub {@linkplain Stub#getMethod() implemented} by {@code method} or null if - * {@code method} does not implement a stub - */ - public Stub asStub(ResolvedJavaMethod method) { - return stubs.get(method); - } - public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) { HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor); assert runtimeCalls != null : descriptor; @@ -895,6 +1234,8 @@ return config.deoptReasonDiv0Check; case RuntimeConstraint: return config.deoptReasonConstraint; + case LoopLimitCheck: + return config.deoptReasonLoopLimitCheck; default: throw GraalInternalError.shouldNotReachHere(); } @@ -904,20 +1245,6 @@ return constant.getPrimitiveAnnotation() != null; } - /** - * Registers an object created by the compiler and referenced by some generated code. HotSpot - * treats oops embedded in code as weak references so without an external strong root, such an - * embedded oop will quickly die. This in turn will cause the nmethod to be unloaded. - */ - public synchronized Object registerGCRoot(Object object) { - Object existing = gcRoots.get(object); - if (existing != null) { - return existing; - } - gcRoots.put(object, object); - return object; - } - @Override public Constant readUnsafeConstant(Kind kind, Object base, long displacement) { switch (kind) { @@ -951,8 +1278,8 @@ public String disassemble(InstalledCode code) { if (code.isValid()) { - long nmethod = ((HotSpotInstalledCode) code).getMethodAddress(); - return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod); + long codeBlob = ((HotSpotInstalledCode) code).getCodeBlob(); + return graalRuntime.getCompilerToVM().disassembleCodeBlob(codeBlob); } return null; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java Mon May 13 17:11:31 2013 +0200 @@ -37,10 +37,10 @@ public class HotSpotSignature extends CompilerObject implements Signature { private static final long serialVersionUID = -2890917956072366116L; - private final List arguments = new ArrayList<>(); + private final List parameters = new ArrayList<>(); private final String returnType; private final String originalString; - private JavaType[] argumentTypes; + private JavaType[] parameterTypes; private JavaType returnTypeCache; public HotSpotSignature(String signature) { @@ -51,7 +51,7 @@ int cur = 1; while (cur < signature.length() && signature.charAt(cur) != ')') { int nextCur = parseSignature(signature, cur); - arguments.add(signature.substring(cur, nextCur)); + parameters.add(signature.substring(cur, nextCur)); cur = nextCur; } @@ -64,6 +64,20 @@ } } + public HotSpotSignature(JavaType returnType, JavaType... parameterTypes) { + this.parameterTypes = parameterTypes.clone(); + this.returnTypeCache = returnType; + this.returnType = returnType.getName(); + StringBuilder sb = new StringBuilder("("); + for (JavaType type : parameterTypes) { + parameters.add(type.getName()); + sb.append(type.getName()); + } + sb.append(")").append(returnType.getName()); + this.originalString = sb.toString(); + assert new HotSpotSignature(originalString).equals(this); + } + private static int parseSignature(String signature, int start) { int cur = start; char first; @@ -96,12 +110,12 @@ @Override public int getParameterCount(boolean withReceiver) { - return arguments.size() + (withReceiver ? 1 : 0); + return parameters.size() + (withReceiver ? 1 : 0); } @Override public Kind getParameterKind(int index) { - return Kind.fromTypeString(arguments.get(index)); + return Kind.fromTypeString(parameters.get(index)); } @Override @@ -115,13 +129,13 @@ @Override public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { - if (argumentTypes == null) { - argumentTypes = new JavaType[arguments.size()]; + if (parameterTypes == null) { + parameterTypes = new JavaType[parameters.size()]; } - JavaType type = argumentTypes[index]; + JavaType type = parameterTypes[index]; if (type == null || !(type instanceof ResolvedJavaType)) { - type = graalRuntime().lookupType(arguments.get(index), (HotSpotResolvedObjectType) accessingClass, false); - argumentTypes[index] = type; + type = graalRuntime().lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false); + parameterTypes[index] = type; } return type; } @@ -149,4 +163,21 @@ return "HotSpotSignature<" + originalString + ">"; } + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotSignature) { + HotSpotSignature other = (HotSpotSignature) obj; + if (other.originalString.equals(originalString)) { + assert other.parameters.equals(parameters); + assert other.returnType.equals(returnType); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return originalString.hashCode(); + } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Mon May 13 17:11:31 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; @@ -38,22 +39,12 @@ * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer * check on the object. */ -public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MonitorReference { - - private final boolean eliminated; +public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter { - private int lockDepth = -1; + private int lockDepth; - public BeginLockScopeNode(boolean eliminated) { + public BeginLockScopeNode(int lockDepth) { super(StampFactory.forWord()); - this.eliminated = eliminated; - } - - public int getLockDepth() { - return lockDepth; - } - - public void setLockDepth(int lockDepth) { this.lockDepth = lockDepth; } @@ -63,8 +54,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override @@ -72,12 +63,10 @@ assert lockDepth != -1; HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); - if (!eliminated) { - Value result = gen.emitAddress(slot); - gen.setResult(this, result); - } + Value result = gen.emitAddress(slot); + gen.setResult(this, result); } @NodeIntrinsic - public static native Word beginLockScope(@ConstantNodeParameter boolean eliminated); + public static native Word beginLockScope(@ConstantNodeParameter int lockDepth); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CRuntimeCall.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Implements a direct call to a C/C++ HotSpot function. + */ +public class CRuntimeCall extends DeoptimizingFixedWithNextNode implements LIRGenLowerable { + + @Input protected final NodeInputList arguments; + + private final Descriptor descriptor; + + public CRuntimeCall(Descriptor descriptor, ValueNode... arguments) { + super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); + this.arguments = new NodeInputList<>(this, arguments); + this.descriptor = descriptor; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); + Value[] args = new Value[arguments.size()]; + for (int i = 0; i < args.length; i++) { + args[i] = gen.operand(arguments.get(i)); + } + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, args); + if (result != null) { + gen.setResult(this, result); + } + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Mon May 13 17:11:31 2013 +0200 @@ -51,9 +51,8 @@ unsafe.putByte(cstring + i, formatBytes[i]); } unsafe.putByte(cstring + formatBytes.length, (byte) 0); - StructuredGraph graph = (StructuredGraph) graph(); - ConstantNode replacement = ConstantNode.forLong(cstring, graph); - graph.replaceFloating(this, replacement); + ConstantNode replacement = ConstantNode.forLong(cstring, graph()); + graph().replaceFloating(this, replacement); } @NodeIntrinsic diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Mon May 13 17:11:31 2013 +0200 @@ -28,26 +28,18 @@ import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}. */ -public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference { +public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable { - private int lockDepth = -1; + private int lockDepth; - public CurrentLockNode() { + public CurrentLockNode(int lockDepth) { super(StampFactory.forWord()); - } - - public int getLockDepth() { - return lockDepth; - } - - public void setLockDepth(int lockDepth) { this.lockDepth = lockDepth; } @@ -62,5 +54,5 @@ } @NodeIntrinsic - public static native Word currentLock(); + public static native Word currentLock(@ConstantNodeParameter int lockDepth); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Removes the current frame and tail calls the uncommon trap routine. + */ +@NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}") +public class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable { + + private final DeoptimizationAction action; + private final DeoptimizationReason reason; + + public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) { + super(StampFactory.forVoid()); + this.action = action; + this.reason = reason; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen).emitDeoptimizeCaller(action, reason); + } + + @NodeIntrinsic + public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason); +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Mon May 13 17:11:31 2013 +0200 @@ -26,14 +26,16 @@ import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.word.*; /** * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a - * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word, Object)} returns - * either the expected value or the compared against value instead of a boolean. + * {@link StateSplit} and it + * {@linkplain #compareAndSwap(Object, long, Word, Word, LocationIdentity)} returns either the + * expected value or the compared against value instead of a boolean. */ public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint { @@ -42,9 +44,9 @@ @Input private ValueNode expectedValue; @Input private ValueNode newValue; - private final Object locationIdentity; + private final LocationIdentity locationIdentity; - public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Object locationIdentity) { + public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) { super(expected.stamp()); this.object = object; this.offset = offset; @@ -70,8 +72,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{locationIdentity}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{locationIdentity}; } @Override @@ -92,5 +94,5 @@ * @return either {@code expectedValue} or the actual value */ @NodeIntrinsic - public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter Object locationIdentity); + public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter LocationIdentity locationIdentity); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Mon May 13 17:11:31 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.compiler.target.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.type.*; /** @@ -44,8 +45,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Mon May 13 17:11:31 2013 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -47,8 +48,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override @@ -69,11 +70,11 @@ ResolvedJavaMethod method = null; ResolvedJavaField methodField = null; ResolvedJavaField metaspaceMethodField = null; - ResolvedJavaField nmethodField = null; + ResolvedJavaField codeBlobField = null; try { method = tool.lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class)); methodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("method")); - nmethodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("nmethod")); + codeBlobField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("codeBlob")); metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod")); } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) { throw new IllegalStateException(e); @@ -82,27 +83,26 @@ for (int i = 0; i < signature.length; i++) { signatureTypes[i] = tool.lookupJavaType(signature[i]); } - final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset(); + final int verifiedEntryPointOffset = HotSpotReplacementsUtil.verifiedEntryPointOffset(); - StructuredGraph g = (StructuredGraph) graph(); - - LoadFieldNode loadnmethod = g.add(new LoadFieldNode(code, nmethodField)); - UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadnmethod, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind)); + LoadFieldNode loadCodeBlob = graph().add(new LoadFieldNode(code, codeBlobField)); + UnsafeLoadNode load = graph().add(new UnsafeLoadNode(loadCodeBlob, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), graalRuntime().getTarget().wordKind)); - LoadFieldNode loadMethod = g.add(new LoadFieldNode(code, methodField)); - LoadFieldNode loadmetaspaceMethod = g.add(new LoadFieldNode(loadMethod, metaspaceMethodField)); + LoadFieldNode loadMethod = graph().add(new LoadFieldNode(code, methodField)); + LoadFieldNode loadmetaspaceMethod = graph().add(new LoadFieldNode(loadMethod, metaspaceMethodField)); - HotSpotIndirectCallTargetNode callTarget = g.add(new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall)); + HotSpotIndirectCallTargetNode callTarget = graph().add( + new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall)); - InvokeNode invoke = g.add(new InvokeNode(callTarget, 0)); + InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0)); invoke.setStateAfter(stateAfter()); - g.replaceFixedWithFixed(this, invoke); + graph().replaceFixedWithFixed(this, invoke); - g.addBeforeFixed(invoke, loadmetaspaceMethod); - g.addBeforeFixed(loadmetaspaceMethod, loadMethod); - g.addBeforeFixed(invoke, load); - g.addBeforeFixed(load, loadnmethod); + graph().addBeforeFixed(invoke, loadmetaspaceMethod); + graph().addBeforeFixed(loadmetaspaceMethod, loadMethod); + graph().addBeforeFixed(invoke, load); + graph().addBeforeFixed(load, loadCodeBlob); return invoke; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Node implementing a call to HotSpot's {@code graal_identityhashcode} stub. - */ -public class IdentityHashCodeStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - @Input private final ValueNode object; - public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class); - - public IdentityHashCodeStubCall(ValueNode object) { - super(StampFactory.forKind(Kind.Int)); - this.object = object; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(IdentityHashCodeStubCall.IDENTITY_HASHCODE); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static int call(Object object) { - return System.identityHashCode(object); - } -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Mon May 13 17:11:31 2013 +0200 @@ -39,16 +39,14 @@ @Input private final ValueNode allocationSize; private final ResolvedJavaType type; private final boolean fillContents; - private final boolean locked; - public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents, boolean locked) { + public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents) { super(StampFactory.exactNonNull(type)); this.memory = memory; this.type = type; this.length = length; this.allocationSize = allocationSize; this.fillContents = fillContents; - this.locked = locked; } public ValueNode memory() { @@ -77,16 +75,11 @@ return fillContents; } - public boolean locked() { - return locked; - } - @Override public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } @NodeIntrinsic - public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents, - @ConstantNodeParameter boolean locked); + public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Mon May 13 17:11:31 2013 +0200 @@ -37,14 +37,12 @@ @Input private final ValueNode memory; private final ResolvedJavaType type; private final boolean fillContents; - private final boolean locked; - public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents, boolean locked) { + public InitializeObjectNode(ValueNode memory, ResolvedJavaType type, boolean fillContents) { super(StampFactory.exactNonNull(type)); this.memory = memory; this.type = type; this.fillContents = fillContents; - this.locked = locked; } public ValueNode memory() { @@ -59,10 +57,6 @@ return fillContents; } - public boolean locked() { - return locked; - } - @Override public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +/** + * Sets up the {@linkplain HotSpotBackend#EXCEPTION_HANDLER_IN_CALLER arguments} expected by an + * exception handler in the caller's frame, removes the current frame and jumps to said handler. + */ +public class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable { + + @Input private ValueNode handlerInCallerPc; + @Input private ValueNode exception; + @Input private ValueNode exceptionPc; + + public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { + super(StampFactory.forVoid()); + this.handlerInCallerPc = handlerInCallerPc; + this.exception = exception; + this.exceptionPc = exceptionPc; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen).emitJumpToExceptionHandlerInCaller(handlerInCallerPc, exception, exceptionPc); + } + + @NodeIntrinsic + public static native void jumpToExceptionHandlerInCaller(Word handlerInCallerPc, Object exception, Word exceptionPc); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -28,29 +28,21 @@ import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** * Node implementing a call to HotSpot's {@code graal_monitorexit} stub. */ -public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable, MonitorReference { +public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode object; private int lockDepth; public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class); - public MonitorExitStubCall(ValueNode object) { + public MonitorExitStubCall(ValueNode object, int lockDepth) { super(StampFactory.forVoid()); this.object = object; - } - - public int getLockDepth() { - return lockDepth; - } - - public void setLockDepth(int lockDepth) { this.lockDepth = lockDepth; } @@ -64,5 +56,5 @@ } @NodeIntrinsic - public static native void call(Object hub); + public static native void call(Object hub, @ConstantNodeParameter int lockDepth); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to the {@code new_array} stub. - */ -public class NewArraySlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input private final ValueNode hub; - @Input private final ValueNode length; - - public static final Descriptor NEW_ARRAY_SLOW = new Descriptor("new_array_slow", false, Object.class, Word.class, int.class); - - public NewArraySlowStubCall(ValueNode hub, ValueNode length) { - super(defaultStamp); - this.hub = hub; - this.length = length; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); - return true; - } - return false; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(Word hub, int length); -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * Node implementing a call to HotSpot's {@code new_instance} stub. - */ -public class NewInstanceSlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { - - private static final Stamp defaultStamp = StampFactory.objectNonNull(); - - @Input private final ValueNode hub; - - public static final Descriptor NEW_INSTANCE_SLOW = new Descriptor("new_instance_slow", false, Object.class, Word.class); - - public NewInstanceSlowStubCall(ValueNode hub) { - super(defaultStamp); - this.hub = hub; - } - - @Override - public boolean inferStamp() { - if (stamp() == defaultStamp && hub.isConstant()) { - updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); - return true; - } - return false; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub)); - gen.setResult(this, result); - } - - @NodeIntrinsic - public static native Object call(Word hub); -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -28,13 +28,14 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** - * Node implementing a call to HotSpot's {@code new_multi_array} stub. + * Node implementing a call to {@link NewMultiArrayStub}. */ public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.hotspot.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +/** + * Modifies the return address of the current frame. + */ +public class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable { + + @Input private ValueNode address; + + public PatchReturnAddressNode(ValueNode address) { + super(StampFactory.forVoid()); + this.address = address; + } + + @Override + public void generate(LIRGeneratorTool gen) { + ((HotSpotLIRGenerator) gen).emitPatchReturnAddress(address); + } + + @NodeIntrinsic + public static native void patchReturnAddress(Word address); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,42 @@ +/* + * 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.hotspot.nodes; + +import com.oracle.graal.hotspot.stubs.*; +import com.oracle.graal.nodes.*; + +/** + * Start node for a {@link Stub}'s graph. + */ +public class StubStartNode extends StartNode { + + private final Stub stub; + + public StubStartNode(Stub stub) { + this.stub = stub; + } + + public Stub getStub() { + return stub; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -30,12 +30,13 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; /** - * Node implementing a call to HotSpot's ThreadIsInterrupted stub. + * Node implementing a call to {@link ThreadIsInterruptedStub}. */ public class ThreadIsInterruptedStubCall extends DeoptimizingStubCall implements LIRGenLowerable { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,7 +27,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; -import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; @@ -38,11 +37,11 @@ */ public final class VMErrorNode extends DeoptimizingStubCall implements LIRGenLowerable { - @Input private ValueNode format; + private final String format; @Input private ValueNode value; public static final Descriptor VM_ERROR = new Descriptor("vm_error", false, void.class, Object.class, Object.class, long.class); - public VMErrorNode(ValueNode format, ValueNode value) { + private VMErrorNode(String format, ValueNode value) { super(StampFactory.forVoid()); this.format = format; this.value = value; @@ -50,21 +49,19 @@ @Override public void generate(LIRGenerator gen) { - String where = "in compiled code for " + MetaUtil.format("%H.%n(%p)", gen.method()); + String whereString = "in compiled code for " + graph(); - HotSpotRuntime runtime = (HotSpotRuntime) gen.getRuntime(); - Constant whereArg = Constant.forObject(runtime.registerGCRoot(where)); - Value formatArg; - if (format.isConstant() && format.kind() == Kind.Object) { - formatArg = Constant.forObject(runtime.registerGCRoot(format.asConstant().asObject())); - } else { - formatArg = gen.operand(format); - } + // As these strings will end up embedded as oops in the code, they + // must be interned or else they will cause the nmethod to be unloaded + // (nmethods are a) weak GC roots and b) unloaded if any of their + // embedded oops become unreachable). + Constant whereArg = Constant.forObject(whereString.intern()); + Constant formatArg = Constant.forObject(format.intern()); RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR); gen.emitCall(stub, stub.getCallingConvention(), null, whereArg, formatArg, gen.operand(value)); } @NodeIntrinsic - public static native void vmError(String format, long value); + public static native void vmError(@ConstantNodeParameter String format, long value); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -26,16 +26,17 @@ import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; /** - * Node implementing a call to HotSpot's object pointer verification stub. + * Call to {@link VerifyOopStub}. */ public class VerifyOopStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode object; - public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, void.class, Object.class); + public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, Object.class, Object.class); public VerifyOopStubCall(ValueNode object) { super(StampFactory.objectNonNull()); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -26,18 +26,19 @@ import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** - * Node implementing a call to HotSpot's {@code graal_monitorenter} stub. + * Node implementing a call to {@link WriteBarrierPostStub}. */ public class WriteBarrierPostStubCall extends FixedWithNextNode implements LIRGenLowerable { @Input private ValueNode object; @Input private ValueNode card; - public static final Descriptor WBPOSTCALL = new Descriptor("wbpostcall", true, void.class, Object.class, Word.class); + public static final Descriptor WRITE_BARRIER_POST = new Descriptor("writeBarrierPost", true, void.class, Object.class, Word.class); public WriteBarrierPostStubCall(ValueNode object, ValueNode card) { super(StampFactory.forVoid()); @@ -47,7 +48,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WBPOSTCALL); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WRITE_BARRIER_POST); gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object), gen.operand(card)); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Mon May 13 17:11:31 2013 +0200 @@ -26,16 +26,17 @@ import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; /** - * Node implementing a call to HotSpot's {@code graal_monitorenter} stub. + * Node implementing a call to {@link WriteBarrierPreStub}. */ public class WriteBarrierPreStubCall extends FixedWithNextNode implements LIRGenLowerable { @Input private ValueNode object; - public static final Descriptor WBPRECALL = new Descriptor("wbprecall", true, void.class, Object.class); + public static final Descriptor WRITE_BARRIER_PRE = new Descriptor("writeBarrierPre", true, void.class, Object.class); public WriteBarrierPreStubCall(ValueNode object) { super(StampFactory.forVoid()); @@ -44,7 +45,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WBPRECALL); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WRITE_BARRIER_PRE); gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object)); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Mon May 13 17:11:31 2013 +0200 @@ -22,20 +22,14 @@ */ package com.oracle.graal.hotspot.phases; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; - import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.*; +import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.java.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -43,29 +37,6 @@ public class OnStackReplacementPhase extends Phase { - public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class); - - public class OSREntryProxyNode extends FloatingNode implements LIRLowerable { - - @Input private ValueNode object; - @Input(notDataflow = true) private final RuntimeCallNode anchor; - - public OSREntryProxyNode(ValueNode object, RuntimeCallNode anchor) { - super(object.stamp()); - this.object = object; - this.anchor = anchor; - } - - public RuntimeCallNode getAnchor() { - return anchor; - } - - @Override - public void generate(LIRGeneratorTool generator) { - generator.setResult(this, generator.operand(object)); - } - } - @Override protected void run(StructuredGraph graph) { if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { @@ -114,39 +85,29 @@ Debug.dump(graph, "OnStackReplacement loop peeling result"); } while (true); - LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind()))); - RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer)); FrameState osrState = osr.stateAfter(); - migrationEnd.setStateAfter(osrState); osr.setStateAfter(null); - + OSRStartNode osrStart = graph.add(new OSRStartNode()); StartNode start = graph.start(); - FixedNode rest = start.next(); - start.setNext(migrationEnd); FixedNode next = osr.next(); osr.setNext(null); - migrationEnd.setNext(next); + osrStart.setNext(next); + graph.setStart(osrStart); + osrStart.setStateAfter(osrState); - FrameState oldStartState = start.stateAfter(); - start.setStateAfter(null); - GraphUtil.killWithUnusedFloatingInputs(oldStartState); - - // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) - int localsOffset = (graph.method().getMaxLocals() - 1) * 8; for (int i = 0; i < osrState.localsSize(); i++) { ValueNode value = osrState.localAt(i); if (value != null) { ProxyNode proxy = (ProxyNode) value; - int size = FrameStateBuilder.stackSlots(value.kind()); - int offset = localsOffset - (i + size - 1) * 8; - UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind())); - OSREntryProxyNode newProxy = graph.add(new OSREntryProxyNode(load, migrationEnd)); - proxy.replaceAndDelete(newProxy); - graph.addBeforeFixed(migrationEnd, load); + /* + * we need to drop the stamp and go back to the kind since the types we see during + * OSR may be too precise (if a branch was not parsed for example). + */ + proxy.replaceAndDelete(graph.unique(new OSRLocalNode(i, StampFactory.forKind(proxy.kind())))); } } - GraphUtil.killCFG(rest); + GraphUtil.killCFG(start); Debug.dump(graph, "OnStackReplacement result"); new DeadCodeEliminationPhase().apply(graph); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -31,193 +31,94 @@ import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; +/** + * Verification phase that checks if, for every write, at least one write barrier is present at all + * paths leading to the previous safepoint. For every write, necessitating a write barrier, a + * bottom-up traversal of the graph is performed up to the previous safepoints via all possible + * paths. If, for a certain path, no write barrier satisfying the processed write is found, an + * assertion is generated. + */ public class WriteBarrierVerificationPhase extends Phase { - private class MemoryMap implements MergeableState { - - private IdentityHashMap> lastMemorySnapshot; - private IdentityHashMap> lastWriteBarrierSnapshot; - - public MemoryMap(MemoryMap memoryMap) { - lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - lastWriteBarrierSnapshot = new IdentityHashMap<>(memoryMap.lastWriteBarrierSnapshot); - } - - public MemoryMap() { - lastMemorySnapshot = new IdentityHashMap<>(); - lastWriteBarrierSnapshot = new IdentityHashMap<>(); - } - - @Override - public String toString() { - return "Map=" + lastMemorySnapshot.toString(); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - if (withStates.size() == 0) { - return true; - } + @Override + protected void run(StructuredGraph graph) { + processWrites(graph); + } - for (MemoryMap other : withStates) { - for (Object otherObject : other.lastMemorySnapshot.keySet()) { - LinkedList currentLocations = lastMemorySnapshot.get(otherObject); - LinkedList otherLocations = other.lastMemorySnapshot.get(otherObject); - if (otherLocations != null) { - if (currentLocations == null) { - currentLocations = new LinkedList<>(); - } - for (LocationNode location : otherLocations) { - if (!currentLocations.contains(location)) { - currentLocations.add(location); - } - } - } - } - for (Object otherObject : other.lastWriteBarrierSnapshot.keySet()) { - LinkedList currentWriteBarriers = lastWriteBarrierSnapshot.get(otherObject); - LinkedList otherWriteBarriers = other.lastWriteBarrierSnapshot.get(otherObject); - if (otherWriteBarriers != null) { - if (currentWriteBarriers == null) { - currentWriteBarriers = new LinkedList<>(); - } - for (SerialWriteBarrier barrier : otherWriteBarriers) { - if (!currentWriteBarriers.contains(barrier)) { - currentWriteBarriers.add(barrier); - } - } - } - } + private static void processWrites(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (isObjectWrite(node)) { + validateWrite(node); } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - } - - @Override - public void afterSplit(BeginNode node) { - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); } } - @Override - protected void run(StructuredGraph graph) { - new PostOrderNodeIterator(graph.start(), new MemoryMap()) { - - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private static void processNode(FixedNode node, MemoryMap state) { - if (node instanceof WriteNode) { - processWriteNode((WriteNode) node, state); - } else if (node instanceof CompareAndSwapNode) { - processCASNode((CompareAndSwapNode) node, state); - } else if (node instanceof SerialWriteBarrier) { - processWriteBarrier((SerialWriteBarrier) node, state); - } else if ((node instanceof DeoptimizingNode)) { - if (((DeoptimizingNode) node).canDeoptimize()) { - validateWriteBarriers(state); - processSafepoint(state); + private static void validateWrite(Node write) { + /* + * The currently validated write is checked in order to discover if it has an appropriate + * attached write barrier. + */ + if (hasAttachedBarrier(write)) { + return; + } + NodeFlood frontier = write.graph().createNodeFlood(); + expandFrontier(frontier, write); + Iterator iterator = frontier.iterator(); + while (iterator.hasNext()) { + Node currentNode = iterator.next(); + assert !isSafepoint(currentNode) : "Write barrier must be present"; + if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (SerialWriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); } } } - private static void processWriteNode(WriteNode node, MemoryMap state) { - if (node.getWriteBarrierType() != WriteBarrierType.NONE) { - LinkedList locations = state.lastMemorySnapshot.get(node.object()); - if (locations == null) { - locations = new LinkedList<>(); - locations.add(node.location()); - state.lastMemorySnapshot.put(node.object(), locations); - } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.location())) { - locations.add(node.location()); - } - } + private static boolean hasAttachedBarrier(Node node) { + return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next()); } - private static void processCASNode(CompareAndSwapNode node, MemoryMap state) { - if (node.getWriteBarrierType() != WriteBarrierType.NONE) { - LinkedList locations = state.lastMemorySnapshot.get(node.object()); - if (locations == null) { - locations = new LinkedList<>(); - locations.add(node.getLocation()); - state.lastMemorySnapshot.put(node.object(), locations); - } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.getLocation())) { - locations.add(node.getLocation()); + private static boolean isObjectWrite(Node node) { + if ((node instanceof WriteNode && (((WriteNode) node).getWriteBarrierType() != WriteBarrierType.NONE)) || + (node instanceof CompareAndSwapNode && (((CompareAndSwapNode) node).getWriteBarrierType() != WriteBarrierType.NONE))) { + return true; + } + return false; + } + + private static void expandFrontier(NodeFlood frontier, Node node) { + for (Node previousNode : node.cfgPredecessors()) { + if (previousNode != null) { + frontier.add(previousNode); } } } - private static void processWriteBarrier(SerialWriteBarrier currentBarrier, MemoryMap state) { - LinkedList writeBarriers = state.lastWriteBarrierSnapshot.get(currentBarrier.getObject()); - if (writeBarriers == null) { - writeBarriers = new LinkedList<>(); - writeBarriers.add(currentBarrier); - state.lastWriteBarrierSnapshot.put(currentBarrier.getObject(), writeBarriers); - } else if (currentBarrier.usePrecise()) { - boolean found = false; - for (SerialWriteBarrier barrier : writeBarriers) { - if (barrier.getLocation() == currentBarrier.getLocation()) { - found = true; - break; - } - } - if (!found) { - writeBarriers.add(currentBarrier); - } - } + private static boolean isSafepoint(Node node) { + /* + * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed + * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write + * barriers inside loops, derived from writes outside loops, can not be permitted. + */ + return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode); } - private static void validateWriteBarriers(MemoryMap state) { - Set objects = state.lastMemorySnapshot.keySet(); - for (Object write : objects) { - LinkedList writeBarriers = state.lastWriteBarrierSnapshot.get(write); - if (writeBarriers == null) { - throw new GraalInternalError("Failed to find any write barrier at safepoint for written object"); - } - /* - * Check the first write barrier of the object to determine if it is precise or not. If - * it is not, the validation for this object has passed (since we had a hit in the write - * barrier hashmap), otherwise we have to ensure the presence of write barriers for - * every written location. - */ - final boolean precise = writeBarriers.getFirst().usePrecise(); - if (precise) { - LinkedList locations = state.lastMemorySnapshot.get(write); - for (LocationNode location : locations) { - boolean found = false; - for (SerialWriteBarrier barrier : writeBarriers) { - if (location == barrier.getLocation()) { - found = true; - break; - } - } - if (!found) { - throw new GraalInternalError("Failed to find write barrier at safepoint for precise written object"); - } - } - } + private static boolean validateBarrier(Node write, SerialWriteBarrier barrier) { + ValueNode writtenObject = null; + LocationNode writtenLocation = null; + if (write instanceof WriteNode) { + writtenObject = ((WriteNode) write).object(); + writtenLocation = ((WriteNode) write).location(); + } else if (write instanceof CompareAndSwapNode) { + writtenObject = ((CompareAndSwapNode) write).object(); + writtenLocation = ((CompareAndSwapNode) write).getLocation(); + } else { + assert false : "Node must be of type requiring a write barrier"; } - } - private static void processSafepoint(MemoryMap state) { - state.lastMemorySnapshot.clear(); - state.lastWriteBarrierSnapshot.clear(); + if ((barrier.getObject() == writtenObject) && (!barrier.usePrecise() || (barrier.usePrecise() && barrier.getLocation() == writtenLocation))) { + return true; + } + return false; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; import com.oracle.graal.api.code.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import java.lang.reflect.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java Mon May 13 17:11:31 2013 +0200 @@ -67,13 +67,12 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - StructuredGraph graph = (StructuredGraph) graph(); ConstantNode target = getConstantCallTarget(tool.getRuntime(), tool.assumptions()); if (target != null) { - graph.replaceFixedWithFloating(this, target); + graph().replaceFixedWithFloating(this, target); } else { - graph.replaceFixedWithFixed(this, createInvoke()); + graph().replaceFixedWithFixed(this, createInvoke()); } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -24,7 +24,7 @@ import static com.oracle.graal.api.code.DeoptimizationAction.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import static com.oracle.graal.replacements.SnippetTemplate.*; @@ -164,7 +164,7 @@ * Lowers a checkcast node. */ public void lower(CheckCastNode checkcast, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) checkcast.graph(); + StructuredGraph graph = checkcast.graph(); ValueNode object = checkcast.object(); HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type(); TypeCheckHints hintInfo = new TypeCheckHints(checkcast.type(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); @@ -200,7 +200,7 @@ * Lowers a dynamic checkcast node. */ public void lower(CheckCastDynamicNode checkcast) { - StructuredGraph graph = (StructuredGraph) checkcast.graph(); + StructuredGraph graph = checkcast.graph(); ValueNode object = checkcast.object(); Arguments args = new Arguments(dynamic); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; import com.oracle.graal.api.code.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import java.lang.reflect.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +//JaCoCo Exclude + +/** + * A collection of methods used in HotSpot snippets, substitutions and stubs. + */ +public class HotSpotReplacementsUtil { + + public static final LocationIdentity ANY_LOCATION = LocationNode.ANY_LOCATION; + public static final LocationIdentity FINAL_LOCATION = LocationNode.FINAL_LOCATION; + + public static HotSpotVMConfig config() { + return graalRuntime().getConfig(); + } + + @Fold + public static boolean useTLAB() { + return config().useTLAB; + } + + @Fold + public static boolean verifyOops() { + return config().verifyOops; + } + + public static final LocationIdentity EXCEPTION_OOP_LOCATION = LocationNode.createLocation("ExceptionOop"); + + /** + * @see HotSpotVMConfig#threadExceptionOopOffset + */ + @Fold + public static int threadExceptionOopOffset() { + return config().threadExceptionOopOffset; + } + + public static final LocationIdentity EXCEPTION_PC_LOCATION = LocationNode.createLocation("ExceptionPc"); + + @Fold + public static int threadExceptionPcOffset() { + return config().threadExceptionPcOffset; + } + + public static final LocationIdentity TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); + + @Fold + public static int threadTlabTopOffset() { + return config().threadTlabTopOffset; + } + + public static final LocationIdentity TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); + + @Fold + private static int threadTlabEndOffset() { + return config().threadTlabEndOffset; + } + + public static final LocationIdentity TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); + + @Fold + private static int threadTlabStartOffset() { + return config().threadTlabStartOffset; + } + + public static final LocationIdentity PENDING_EXCEPTION_LOCATION = LocationNode.createLocation("PendingException"); + + /** + * @see HotSpotVMConfig#pendingExceptionOffset + */ + @Fold + private static int threadPendingExceptionOffset() { + return config().pendingExceptionOffset; + } + + public static final LocationIdentity OBJECT_RESULT_LOCATION = LocationNode.createLocation("ObjectResult"); + + @Fold + private static int objectResultOffset() { + return config().threadObjectResultOffset; + } + + /** + * @see HotSpotVMConfig#threadExceptionOopOffset + */ + public static Object readExceptionOop(Word thread) { + return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION); + } + + public static Word readExceptionPc(Word thread) { + return thread.readWord(threadExceptionPcOffset(), EXCEPTION_PC_LOCATION); + } + + /** + * @see HotSpotVMConfig#threadExceptionOopOffset + */ + public static void writeExceptionOop(Word thread, Object value) { + thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION); + } + + public static void writeExceptionPc(Word thread, Word value) { + thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION); + } + + public static Word readTlabTop(Word thread) { + return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); + } + + public static Word readTlabEnd(Word thread) { + return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); + } + + public static Word readTlabStart(Word thread) { + return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); + } + + public static void writeTlabTop(Word thread, Word top) { + thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); + } + + public static void initializeTlab(Word thread, Word start, Word end) { + thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); + thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); + thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); + } + + /** + * Clears the pending exception for the given thread. + * + * @return {@code true} if there was a pending exception + */ + public static boolean clearPendingException(Word thread) { + boolean result = thread.readObject(threadPendingExceptionOffset(), PENDING_EXCEPTION_LOCATION) != null; + thread.writeObject(threadPendingExceptionOffset(), null); + return result; + } + + /** + * Gets and clears the object result from a runtime call stored in a thread local. + * + * @return the object that was in the thread local + */ + public static Object getAndClearObjectResult(Word thread) { + Object result = thread.readObject(objectResultOffset(), OBJECT_RESULT_LOCATION); + thread.writeObject(objectResultOffset(), null); + return result; + } + + @Fold + public static int threadObjectOffset() { + return config().threadObjectOffset; + } + + @Fold + public static int osThreadOffset() { + return config().osThreadOffset; + } + + @Fold + public static int osThreadInterruptedOffset() { + return config().osThreadInterruptedOffset; + } + + @Fold + public static Kind wordKind() { + return graalRuntime().getTarget().wordKind; + } + + @Fold + public static Register threadRegister() { + return graalRuntime().getRuntime().threadRegister(); + } + + @Fold + public static Register stackPointerRegister() { + return graalRuntime().getRuntime().stackPointerRegister(); + } + + @Fold + public static int wordSize() { + return graalRuntime().getTarget().wordSize; + } + + @Fold + public static int pageSize() { + return Unsafe.getUnsafe().pageSize(); + } + + public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); + + @Fold + public static int prototypeMarkWordOffset() { + return config().prototypeMarkWordOffset; + } + + @Fold + public static long arrayPrototypeMarkWord() { + return config().arrayPrototypeMarkWord; + } + + @Fold + public static int klassAccessFlagsOffset() { + return config().klassAccessFlagsOffset; + } + + @Fold + private static int klassLayoutHelperOffset() { + return config().klassLayoutHelperOffset; + } + + public static int readLayoutHelper(Word hub) { + return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); + } + + @Fold + public static int arrayKlassLayoutHelperIdentifier() { + return config().arrayKlassLayoutHelperIdentifier; + } + + @Fold + public static int arrayKlassComponentMirrorOffset() { + return config().arrayKlassComponentMirrorOffset; + } + + @Fold + public static int klassSuperKlassOffset() { + return config().klassSuperKlassOffset; + } + + public static final LocationIdentity MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); + + @Fold + public static int markOffset() { + return config().markOffset; + } + + public static final LocationIdentity HUB_LOCATION = LocationNode.createLocation("Hub"); + + @Fold + private static int hubOffset() { + return config().hubOffset; + } + + public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { + memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); + memory.writeWord(hubOffset(), hub, HUB_LOCATION); + } + + @Fold + public static int unlockedMask() { + return config().unlockedMask; + } + + /** + * Mask for a biasable, locked or unlocked mark word. + * + *
    +     * +----------------------------------+-+-+
    +     * |                                 1|1|1|
    +     * +----------------------------------+-+-+
    +     * 
    + * + */ + @Fold + public static int biasedLockMaskInPlace() { + return config().biasedLockMaskInPlace; + } + + @Fold + public static int epochMaskInPlace() { + return config().epochMaskInPlace; + } + + /** + * Pattern for a biasable, unlocked mark word. + * + *
    +     * +----------------------------------+-+-+
    +     * |                                 1|0|1|
    +     * +----------------------------------+-+-+
    +     * 
    + * + */ + @Fold + public static int biasedLockPattern() { + return config().biasedLockPattern; + } + + @Fold + public static int ageMaskInPlace() { + return config().ageMaskInPlace; + } + + @Fold + public static int metaspaceArrayLengthOffset() { + return config().metaspaceArrayLengthOffset; + } + + @Fold + public static int metaspaceArrayBaseOffset() { + return config().metaspaceArrayBaseOffset; + } + + @Fold + public static int arrayLengthOffset() { + return config().arrayLengthOffset; + } + + @Fold + public static int arrayBaseOffset(Kind elementKind) { + return HotSpotRuntime.getArrayBaseOffset(elementKind); + } + + @Fold + public static int arrayIndexScale(Kind elementKind) { + return HotSpotRuntime.getArrayIndexScale(elementKind); + } + + @Fold + public static int cardTableShift() { + return config().cardtableShift; + } + + @Fold + public static long cardTableStart() { + return config().cardtableStartAddress; + } + + @Fold + public static int g1CardQueueIndexOffset() { + return config().g1CardQueueIndexOffset; + } + + @Fold + public static int g1CardQueueBufferOffset() { + return config().g1CardQueueBufferOffset; + } + + @Fold + public static int logOfHRGrainBytes() { + return config().logOfHRGrainBytes; + } + + @Fold + public static int g1SATBQueueMarkingOffset() { + return config().g1SATBQueueMarkingOffset; + } + + @Fold + public static int g1SATBQueueIndexOffset() { + return config().g1SATBQueueIndexOffset; + } + + @Fold + public static int g1SATBQueueBufferOffset() { + return config().g1SATBQueueBufferOffset; + } + + @Fold + public static int superCheckOffsetOffset() { + return config().superCheckOffsetOffset; + } + + public static final LocationIdentity SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); + + @Fold + public static int secondarySuperCacheOffset() { + return config().secondarySuperCacheOffset; + } + + public static final LocationIdentity SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); + + @Fold + public static int secondarySupersOffset() { + return config().secondarySupersOffset; + } + + public static final LocationIdentity DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); + + @Fold + public static int lockDisplacedMarkOffset() { + return config().basicLockDisplacedHeaderOffset; + } + + @Fold + public static boolean useBiasedLocking() { + return config().useBiasedLocking; + } + + @Fold + public static boolean useG1GC() { + return config().useG1GC; + } + + @Fold + static int uninitializedIdentityHashCodeValue() { + return config().uninitializedIdentityHashCodeValue; + } + + @Fold + static int identityHashCodeShift() { + return config().identityHashCodeShift; + } + + /** + * Loads the hub from a object, null checking it first. + */ + public static Word loadHub(Object object) { + return loadHubIntrinsic(object, wordKind()); + } + + public static Object verifyOop(Object object) { + if (verifyOops()) { + VerifyOopStubCall.call(object); + } + return object; + } + + /** + * Gets the value of the stack pointer register as a Word. + */ + public static Word stackPointer() { + return registerAsWord(stackPointerRegister(), true, false); + } + + /** + * Gets the value of the thread register as a Word. + */ + public static Word thread() { + return registerAsWord(threadRegister(), true, false); + } + + public static Word loadWordFromObject(Object object, int offset) { + return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); + } + + @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) + public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); + + @SuppressWarnings("unused") + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind) { + return Word.box(unsafeReadWord(object, offset + displacement)); + } + + @SuppressWarnings("unused") + @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) + static Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word) { + return Word.box(unsafeReadWord(object, hubOffset())); + } + + @Fold + public static int log2WordSize() { + return CodeUtil.log2(wordSize()); + } + + public static final LocationIdentity CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); + + @Fold + public static int klassStateOffset() { + return config().klassStateOffset; + } + + @Fold + public static int klassStateFullyInitialized() { + return config().klassStateFullyInitialized; + } + + @Fold + public static int klassModifierFlagsOffset() { + return config().klassModifierFlagsOffset; + } + + @Fold + public static int klassOffset() { + return config().klassOffset; + } + + @Fold + public static int classMirrorOffset() { + return config().classMirrorOffset; + } + + @Fold + public static int klassInstanceSizeOffset() { + return config().klassInstanceSizeOffset; + } + + public static final LocationIdentity HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); + + @Fold + public static long heapTopAddress() { + return config().heapTopAddress; + } + + public static final LocationIdentity HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); + + @Fold + public static long heapEndAddress() { + return config().heapEndAddress; + } + + @Fold + public static long tlabIntArrayMarkWord() { + return config().tlabIntArrayMarkWord; + } + + @Fold + public static boolean inlineContiguousAllocationSupported() { + return config().inlineContiguousAllocationSupported; + } + + @Fold + public static int tlabAlignmentReserveInHeapWords() { + return config().tlabAlignmentReserve; + } + + public static final LocationIdentity TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); + + @Fold + public static int threadTlabSizeOffset() { + return config().threadTlabSizeOffset; + } + + public static final LocationIdentity TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); + + @Fold + public static int threadAllocatedBytesOffset() { + return config().threadAllocatedBytesOffset; + } + + public static final LocationIdentity TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); + + @Fold + public static int tlabRefillWasteLimitOffset() { + return config().tlabRefillWasteLimitOffset; + } + + public static final LocationIdentity TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); + + @Fold + public static int tlabNumberOfRefillsOffset() { + return config().tlabNumberOfRefillsOffset; + } + + public static final LocationIdentity TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); + + @Fold + public static int tlabFastRefillWasteOffset() { + return config().tlabFastRefillWasteOffset; + } + + public static final LocationIdentity TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); + + @Fold + public static int tlabSlowAllocationsOffset() { + return config().tlabSlowAllocationsOffset; + } + + @Fold + public static int tlabRefillWasteIncrement() { + return config().tlabRefillWasteIncrement; + } + + @Fold + public static boolean tlabStats() { + return config().tlabStats; + } + + @Fold + public static int layoutHelperOffset() { + return config().layoutHelperOffset; + } + + @Fold + public static int layoutHelperHeaderSizeShift() { + return config().layoutHelperHeaderSizeShift; + } + + @Fold + public static int layoutHelperHeaderSizeMask() { + return config().layoutHelperHeaderSizeMask; + } + + @Fold + public static int layoutHelperLog2ElementSizeShift() { + return config().layoutHelperLog2ElementSizeShift; + } + + @Fold + public static int layoutHelperLog2ElementSizeMask() { + return config().layoutHelperLog2ElementSizeMask; + } + + @Fold + public static int layoutHelperElementTypeShift() { + return config().layoutHelperElementTypeShift; + } + + @Fold + public static int layoutHelperElementTypeMask() { + return config().layoutHelperElementTypeMask; + } + + @Fold + public static int layoutHelperElementTypePrimitiveInPlace() { + return config().layoutHelperElementTypePrimitiveInPlace; + } + + static { + assert arrayIndexScale(Kind.Byte) == 1; + assert arrayIndexScale(Kind.Boolean) == 1; + assert arrayIndexScale(Kind.Char) == 2; + assert arrayIndexScale(Kind.Short) == 2; + assert arrayIndexScale(Kind.Int) == 4; + assert arrayIndexScale(Kind.Long) == 8; + assert arrayIndexScale(Kind.Float) == 4; + assert arrayIndexScale(Kind.Double) == 8; + } + + static int computeHashCode(Object x) { + Word mark = loadWordFromObject(x, markOffset()); + + // this code is independent from biased locking (although it does not look that way) + final Word biasedLock = mark.and(biasedLockMaskInPlace()); + if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) { + int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue(); + if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) { + return hash; + } + } + + return identityHashCode(IDENTITY_HASHCODE, x); + } + + public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class); + + @SuppressWarnings("unused") + @NodeIntrinsic(RuntimeCallNode.class) + public static int identityHashCode(@ConstantNodeParameter Descriptor descriptor, Object object) { + return System.identityHashCode(object); + } + + @Fold + public static int verifiedEntryPointOffset() { + return config().nmethodEntryOffset; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,625 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.replacements; - -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.Snippet.Fold; -import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; - -//JaCoCo Exclude - -/** - * A collection of methods used in HotSpot snippets and substitutions. - */ -public class HotSpotSnippetUtils { - - public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION; - public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; - - public static HotSpotVMConfig config() { - return graalRuntime().getConfig(); - } - - @Fold - public static boolean useTLAB() { - return config().useTLAB; - } - - @Fold - public static boolean verifyOops() { - return config().verifyOops; - } - - public static final Object EXCEPTION_OOP_LOCATION = LocationNode.createLocation("ExceptionOop"); - - @Fold - public static int threadExceptionOopOffset() { - return config().threadExceptionOopOffset; - } - - public static final Object EXCEPTION_PC_LOCATION = LocationNode.createLocation("ExceptionPc"); - - @Fold - public static int threadExceptionPcOffset() { - return config().threadExceptionPcOffset; - } - - public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); - - @Fold - public static int threadTlabTopOffset() { - return config().threadTlabTopOffset; - } - - public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); - - @Fold - private static int threadTlabEndOffset() { - return config().threadTlabEndOffset; - } - - public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); - - @Fold - private static int threadTlabStartOffset() { - return config().threadTlabStartOffset; - } - - public static Object readExceptionOop(Word thread) { - return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION); - } - - public static void writeExceptionOop(Word thread, Object value) { - thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION); - } - - public static void writeExceptionPc(Word thread, Word value) { - thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION); - } - - public static Word readTlabTop(Word thread) { - return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); - } - - public static Word readTlabEnd(Word thread) { - return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); - } - - public static Word readTlabStart(Word thread) { - return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); - } - - public static void writeTlabTop(Word thread, Word top) { - thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); - } - - public static void initializeTlab(Word thread, Word start, Word end) { - thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); - thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); - thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); - } - - @Fold - public static int threadObjectOffset() { - return config().threadObjectOffset; - } - - @Fold - public static int osThreadOffset() { - return config().osThreadOffset; - } - - @Fold - public static int osThreadInterruptedOffset() { - return config().osThreadInterruptedOffset; - } - - @Fold - public static Kind wordKind() { - return graalRuntime().getTarget().wordKind; - } - - @Fold - public static Register threadRegister() { - return graalRuntime().getRuntime().threadRegister(); - } - - @Fold - public static Register stackPointerRegister() { - return graalRuntime().getRuntime().stackPointerRegister(); - } - - @Fold - public static int wordSize() { - return graalRuntime().getTarget().wordSize; - } - - @Fold - public static int pageSize() { - return Unsafe.getUnsafe().pageSize(); - } - - public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); - - @Fold - public static int prototypeMarkWordOffset() { - return config().prototypeMarkWordOffset; - } - - @Fold - public static long arrayPrototypeMarkWord() { - return config().arrayPrototypeMarkWord; - } - - @Fold - public static int klassAccessFlagsOffset() { - return config().klassAccessFlagsOffset; - } - - @Fold - private static int klassLayoutHelperOffset() { - return config().klassLayoutHelperOffset; - } - - public static int readLayoutHelper(Word hub) { - return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); - } - - @Fold - public static int arrayKlassLayoutHelperIdentifier() { - return config().arrayKlassLayoutHelperIdentifier; - } - - @Fold - public static int arrayKlassComponentMirrorOffset() { - return config().arrayKlassComponentMirrorOffset; - } - - @Fold - public static int klassSuperKlassOffset() { - return config().klassSuperKlassOffset; - } - - public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); - - @Fold - public static int markOffset() { - return config().markOffset; - } - - public static final Object HUB_LOCATION = LocationNode.createLocation("Hub"); - - @Fold - private static int hubOffset() { - return config().hubOffset; - } - - public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { - memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); - memory.writeWord(hubOffset(), hub, HUB_LOCATION); - } - - @Fold - public static int unlockedMask() { - return config().unlockedMask; - } - - /** - * Mask for a biasable, locked or unlocked mark word. - * - *
    -     * +----------------------------------+-+-+
    -     * |                                 1|1|1|
    -     * +----------------------------------+-+-+
    -     * 
    - * - */ - @Fold - public static int biasedLockMaskInPlace() { - return config().biasedLockMaskInPlace; - } - - @Fold - public static int epochMaskInPlace() { - return config().epochMaskInPlace; - } - - /** - * Pattern for a biasable, unlocked mark word. - * - *
    -     * +----------------------------------+-+-+
    -     * |                                 1|0|1|
    -     * +----------------------------------+-+-+
    -     * 
    - * - */ - @Fold - public static int biasedLockPattern() { - return config().biasedLockPattern; - } - - @Fold - public static int ageMaskInPlace() { - return config().ageMaskInPlace; - } - - @Fold - public static int metaspaceArrayLengthOffset() { - return config().metaspaceArrayLengthOffset; - } - - @Fold - public static int metaspaceArrayBaseOffset() { - return config().metaspaceArrayBaseOffset; - } - - @Fold - public static int arrayLengthOffset() { - return config().arrayLengthOffset; - } - - @Fold - public static int arrayBaseOffset(Kind elementKind) { - return HotSpotRuntime.getArrayBaseOffset(elementKind); - } - - @Fold - public static int arrayIndexScale(Kind elementKind) { - return HotSpotRuntime.getArrayIndexScale(elementKind); - } - - @Fold - public static int cardTableShift() { - return config().cardtableShift; - } - - @Fold - public static long cardTableStart() { - return config().cardtableStartAddress; - } - - @Fold - public static int g1CardQueueIndexOffset() { - return config().g1CardQueueIndexOffset; - } - - @Fold - public static int g1CardQueueBufferOffset() { - return config().g1CardQueueBufferOffset; - } - - @Fold - public static int logOfHRGrainBytes() { - return config().logOfHRGrainBytes; - } - - @Fold - public static int g1SATBQueueMarkingOffset() { - return config().g1SATBQueueMarkingOffset; - } - - @Fold - public static int g1SATBQueueIndexOffset() { - return config().g1SATBQueueIndexOffset; - } - - @Fold - public static int g1SATBQueueBufferOffset() { - return config().g1SATBQueueBufferOffset; - } - - @Fold - public static int superCheckOffsetOffset() { - return config().superCheckOffsetOffset; - } - - public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); - - @Fold - public static int secondarySuperCacheOffset() { - return config().secondarySuperCacheOffset; - } - - public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); - - @Fold - public static int secondarySupersOffset() { - return config().secondarySupersOffset; - } - - public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); - - @Fold - public static int lockDisplacedMarkOffset() { - return config().basicLockDisplacedHeaderOffset; - } - - @Fold - public static boolean useBiasedLocking() { - return config().useBiasedLocking; - } - - @Fold - public static boolean useG1GC() { - return config().useG1GC; - } - - @Fold - static int uninitializedIdentityHashCodeValue() { - return config().uninitializedIdentityHashCodeValue; - } - - @Fold - static int identityHashCodeShift() { - return config().identityHashCodeShift; - } - - /** - * Loads the hub from a object, null checking it first. - */ - public static Word loadHub(Object object) { - return loadHubIntrinsic(object, wordKind()); - } - - public static Object verifyOop(Object object) { - if (verifyOops()) { - VerifyOopStubCall.call(object); - } - return object; - } - - /** - * Gets the value of the stack pointer register as a Word. - */ - public static Word stackPointer() { - return HotSpotSnippetUtils.registerAsWord(stackPointerRegister(), true, false); - } - - /** - * Gets the value of the thread register as a Word. - */ - public static Word thread() { - return HotSpotSnippetUtils.registerAsWord(threadRegister(), true, false); - } - - public static Word loadWordFromObject(Object object, int offset) { - return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); - } - - @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) - public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); - - @SuppressWarnings("unused") - @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) - private static Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind) { - return Word.box(unsafeReadWord(object, offset + displacement)); - } - - @SuppressWarnings("unused") - @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) - static Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word) { - return Word.box(unsafeReadWord(object, hubOffset())); - } - - @Fold - public static int log2WordSize() { - return CodeUtil.log2(wordSize()); - } - - public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); - - @Fold - public static int klassStateOffset() { - return config().klassStateOffset; - } - - @Fold - public static int klassStateFullyInitialized() { - return config().klassStateFullyInitialized; - } - - @Fold - public static int klassModifierFlagsOffset() { - return config().klassModifierFlagsOffset; - } - - @Fold - public static int klassOffset() { - return config().klassOffset; - } - - @Fold - public static int classMirrorOffset() { - return config().classMirrorOffset; - } - - @Fold - public static int klassInstanceSizeOffset() { - return config().klassInstanceSizeOffset; - } - - public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); - - @Fold - public static long heapTopAddress() { - return config().heapTopAddress; - } - - public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); - - @Fold - public static long heapEndAddress() { - return config().heapEndAddress; - } - - @Fold - public static long tlabIntArrayMarkWord() { - return config().tlabIntArrayMarkWord; - } - - @Fold - public static boolean inlineContiguousAllocationSupported() { - return config().inlineContiguousAllocationSupported; - } - - @Fold - public static int tlabAlignmentReserveInHeapWords() { - return config().tlabAlignmentReserve; - } - - public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); - - @Fold - public static int threadTlabSizeOffset() { - return config().threadTlabSizeOffset; - } - - public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); - - @Fold - public static int threadAllocatedBytesOffset() { - return config().threadAllocatedBytesOffset; - } - - public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); - - @Fold - public static int tlabRefillWasteLimitOffset() { - return config().tlabRefillWasteLimitOffset; - } - - public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); - - @Fold - public static int tlabNumberOfRefillsOffset() { - return config().tlabNumberOfRefillsOffset; - } - - public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); - - @Fold - public static int tlabFastRefillWasteOffset() { - return config().tlabFastRefillWasteOffset; - } - - public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); - - @Fold - public static int tlabSlowAllocationsOffset() { - return config().tlabSlowAllocationsOffset; - } - - @Fold - public static int tlabRefillWasteIncrement() { - return config().tlabRefillWasteIncrement; - } - - @Fold - public static boolean tlabStats() { - return config().tlabStats; - } - - @Fold - public static int layoutHelperOffset() { - return config().layoutHelperOffset; - } - - @Fold - public static int layoutHelperHeaderSizeShift() { - return config().layoutHelperHeaderSizeShift; - } - - @Fold - public static int layoutHelperHeaderSizeMask() { - return config().layoutHelperHeaderSizeMask; - } - - @Fold - public static int layoutHelperLog2ElementSizeShift() { - return config().layoutHelperLog2ElementSizeShift; - } - - @Fold - public static int layoutHelperLog2ElementSizeMask() { - return config().layoutHelperLog2ElementSizeMask; - } - - @Fold - public static int layoutHelperElementTypeShift() { - return config().layoutHelperElementTypeShift; - } - - @Fold - public static int layoutHelperElementTypeMask() { - return config().layoutHelperElementTypeMask; - } - - @Fold - public static int layoutHelperElementTypePrimitiveInPlace() { - return config().layoutHelperElementTypePrimitiveInPlace; - } - - static { - assert arrayIndexScale(Kind.Byte) == 1; - assert arrayIndexScale(Kind.Boolean) == 1; - assert arrayIndexScale(Kind.Char) == 2; - assert arrayIndexScale(Kind.Short) == 2; - assert arrayIndexScale(Kind.Int) == 4; - assert arrayIndexScale(Kind.Long) == 8; - assert arrayIndexScale(Kind.Float) == 4; - assert arrayIndexScale(Kind.Double) == 8; - } - - static int computeHashCode(Object x) { - Word mark = loadWordFromObject(x, markOffset()); - - // this code is independent from biased locking (although it does not look that way) - final Word biasedLock = mark.and(biasedLockMaskInPlace()); - if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask())))) { - int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue(); - if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue())) { - return hash; - } - } - - return IdentityHashCodeStubCall.call(x); - } - - @Fold - public static int verifiedEntryPointOffset() { - return config().nmethodEntryOffset; - } -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import static com.oracle.graal.replacements.SnippetTemplate.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -26,7 +26,7 @@ import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.SnippetTemplate.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; @@ -37,10 +37,10 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; @@ -76,7 +76,7 @@ public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); @Snippet - public static void monitorenter(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { + public static void monitorenter(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { verifyOop(object); if (checkNull && object == null) { @@ -86,7 +86,7 @@ // Load the mark word - this includes a null-check on object final Word mark = loadWordFromObject(object, markOffset()); - final Word lock = beginLockScope(false); + final Word lock = beginLockScope(lockDepth); trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); trace(trace, " lock: 0x%016lx\n", lock); @@ -150,7 +150,7 @@ Word biasedMark = unbiasedMark.or(thread); trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) { + if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:acquired}", object); return; @@ -170,7 +170,7 @@ // the bias from one thread to another directly in this situation. Word biasedMark = prototypeMarkWord.or(thread); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (probability(VERY_FAST_DEOPT_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) { + if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:transfer}", object); return; @@ -248,17 +248,11 @@ } } - @Snippet - public static void monitorenterEliminated() { - incCounter(); - beginLockScope(true); - } - /** * Calls straight out to the monitorenter stub. */ @Snippet - public static void monitorenterStub(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { + public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { verifyOop(object); incCounter(); if (checkNull && object == null) { @@ -266,13 +260,13 @@ } // BeginLockScope nodes do not read from object so a use of object // cannot float about the null check above - final Word lock = beginLockScope(false); + final Word lock = beginLockScope(lockDepth); traceObject(trace, "+lock{stub}", object); MonitorEnterStubCall.call(object, lock); } @Snippet - public static void monitorexit(Object object, @ConstantParameter boolean trace) { + public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); if (useBiasedLocking()) { // Check for biased locking unlock case, which is a no-op @@ -291,7 +285,7 @@ } } - final Word lock = CurrentLockNode.currentLock(); + final Word lock = CurrentLockNode.currentLock(lockDepth); // Load displaced mark final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION); @@ -309,7 +303,7 @@ // The object's mark word was not pointing to the displaced header, // we do unlocking via runtime call. traceObject(trace, "-lock{stub}", object); - MonitorExitStubCall.call(object); + MonitorExitStubCall.call(object, lockDepth); } else { traceObject(trace, "-lock{cas}", object); } @@ -322,16 +316,10 @@ * Calls straight out to the monitorexit stub. */ @Snippet - public static void monitorexitStub(Object object, @ConstantParameter boolean trace) { + public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) { verifyOop(object); traceObject(trace, "-lock{stub}", object); - MonitorExitStubCall.call(object); - endLockScope(); - decCounter(); - } - - @Snippet - public static void monitorexitEliminated() { + MonitorExitStubCall.call(object, lockDepth); endLockScope(); decCounter(); } @@ -356,7 +344,7 @@ */ private static final boolean ENABLE_BREAKPOINT = false; - private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); + private static final LocationIdentity MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); @NodeIntrinsic(BreakpointNode.class) static native void bkpt(Object object, Word mark, Word tmp, Word value); @@ -384,7 +372,7 @@ } @Snippet - private static void checkCounter(String errMsg) { + private static void checkCounter(@ConstantParameter String errMsg) { final Word counter = MonitorCounterNode.counter(); final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); if (count != 0) { @@ -398,8 +386,6 @@ private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit"); private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub"); private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub"); - private final SnippetInfo monitorenterEliminated = snippet(MonitorSnippets.class, "monitorenterEliminated"); - private final SnippetInfo monitorexitEliminated = snippet(MonitorSnippets.class, "monitorexitEliminated"); private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter"); private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter"); @@ -411,23 +397,21 @@ } public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) monitorenterNode.graph(); + StructuredGraph graph = monitorenterNode.graph(); checkBalancedMonitors(graph); FrameState stateAfter = monitorenterNode.stateAfter(); Arguments args; - if (monitorenterNode.eliminated()) { - args = new Arguments(monitorenterEliminated); + if (useFastLocking) { + args = new Arguments(monitorenter); } else { - if (useFastLocking) { - args = new Arguments(monitorenter); - } else { - args = new Arguments(monitorenterStub); - } - args.add("object", monitorenterNode.object()); - args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull()); - args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + args = new Arguments(monitorenterStub); } + args.add("object", monitorenterNode.object()); + args.addConst("lockDepth", monitorenterNode.getLockDepth()); + args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull()); + boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod); Map nodes = template(args).instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, args); @@ -436,28 +420,22 @@ BeginLockScopeNode begin = (BeginLockScopeNode) n; begin.setStateAfter(stateAfter); } - if (n instanceof MonitorReference) { - ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth()); - } } } public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) monitorexitNode.graph(); + StructuredGraph graph = monitorexitNode.graph(); FrameState stateAfter = monitorexitNode.stateAfter(); Arguments args; - if (monitorexitNode.eliminated()) { - args = new Arguments(monitorexitEliminated); + if (useFastLocking) { + args = new Arguments(monitorexit); } else { - if (useFastLocking) { - args = new Arguments(monitorexit); - } else { - args = new Arguments(monitorexitStub); - } - args.add("object", monitorexitNode.object()); - args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + args = new Arguments(monitorexitStub); } + args.add("object", monitorexitNode.object()); + args.addConst("lockDepth", monitorexitNode.getLockDepth()); + args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); Map nodes = template(args).instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, args); @@ -466,9 +444,6 @@ EndLockScopeNode end = (EndLockScopeNode) n; end.setStateAfter(stateAfter); } - if (n instanceof MonitorReference) { - ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth()); - } } } @@ -522,7 +497,7 @@ List rets = graph.getNodes().filter(ReturnNode.class).snapshot(); for (ReturnNode ret : rets) { returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass()); - Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"); + String msg = "unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"; ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph); callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType)); invoke = graph.add(new InvokeNode(callTarget, 0)); @@ -530,7 +505,12 @@ FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false); invoke.setStateAfter(graph.add(stateAfter)); graph.addBeforeFixed(ret, invoke); - inlineeGraph = replacements.getSnippet(checkCounter.getMethod()); + + Arguments args = new Arguments(checkCounter); + args.addConst("errMsg", msg); + inlineeGraph = template(args).copySpecializedGraph(); + + // inlineeGraph = replacements.getSnippet(checkCounter.getMethod()); InliningUtil.inline(invoke, inlineeGraph, false); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.api.code.UnsignedMath.*; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import static com.oracle.graal.replacements.SnippetTemplate.*; @@ -72,18 +72,14 @@ } @Snippet - public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) { + public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents) { Object result; if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) { new_stub.inc(); result = NewInstanceStubCall.call(hub); } else { - if (locked) { - formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); - } else { - formatObject(hub, size, memory, prototypeMarkWord, fillContents); - } + formatObject(hub, size, memory, prototypeMarkWord, fillContents); result = memory.toObject(); } /* @@ -95,16 +91,7 @@ } @Snippet - public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents, - @ConstantParameter boolean locked) { - if (locked) { - return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents); - } else { - return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents); - } - } - - private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) { + public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents) { Object result; if (probability(SLOW_PATH_PROBABILITY, memory.equal(0))) { newarray_stub.inc(); @@ -132,7 +119,7 @@ } int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); Word memory = TLABAllocateNode.allocateVariableSize(allocationSize); - return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents, false); + return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents); } /** @@ -229,7 +216,7 @@ */ @SuppressWarnings("unused") public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newInstanceNode.graph(); + StructuredGraph graph = newInstanceNode.graph(); HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass(); ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); int size = instanceSize(type); @@ -243,7 +230,7 @@ graph.addBeforeFixed(newInstanceNode, tlabAllocateNode); memory = tlabAllocateNode; } - InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked())); + InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents())); graph.replaceFixedWithFixed(newInstanceNode, initializeNode); } @@ -252,7 +239,7 @@ */ @SuppressWarnings("unused") public void lower(NewArrayNode newArrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newArrayNode.graph(); + StructuredGraph graph = newArrayNode.graph(); ValueNode lengthNode = newArrayNode.length(); TLABAllocateNode tlabAllocateNode; ResolvedJavaType elementType = newArrayNode.elementType(); @@ -261,7 +248,7 @@ final int alignment = target.wordSize; final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null; - int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); + int log2ElementSize = CodeUtil.log2(target.arch.getSizeInBytes(elementKind)); if (!useTLAB) { ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph); /* @@ -269,7 +256,7 @@ * anyway for both allocation and initialization - it just needs to be non-null */ ConstantNode size = ConstantNode.forInt(-1, graph); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents())); graph.replaceFixedWithFixed(newArrayNode, initializeNode); } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { // Calculate aligned size @@ -277,7 +264,7 @@ ConstantNode sizeNode = ConstantNode.forInt(size, graph); tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); graph.addBeforeFixed(newArrayNode, tlabAllocateNode); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents())); graph.replaceFixedWithFixed(newArrayNode, initializeNode); } else { Arguments args = new Arguments(allocateArrayAndInitialize); @@ -296,7 +283,7 @@ @SuppressWarnings("unused") public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); + StructuredGraph graph = tlabAllocateNode.graph(); ValueNode size = tlabAllocateNode.size(); Arguments args = new Arguments(allocate).add("size", size); @@ -307,7 +294,7 @@ @SuppressWarnings("unused") public void lower(InitializeObjectNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + StructuredGraph graph = initializeNode.graph(); HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); assert !type.isArray(); ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); @@ -319,7 +306,6 @@ args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("size", size).addConst("fillContents", initializeNode.fillContents()); - args.addConst("locked", initializeNode.locked()); SnippetTemplate template = template(args); Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args); @@ -328,7 +314,7 @@ @SuppressWarnings("unused") public void lower(InitializeArrayNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + StructuredGraph graph = initializeNode.graph(); HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); ResolvedJavaType elementType = type.getComponentType(); assert elementType != null; @@ -345,7 +331,6 @@ args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("headerSize", headerSize); args.addConst("fillContents", initializeNode.fillContents()); - args.addConst("locked", initializeNode.locked()); SnippetTemplate template = template(args); Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args); @@ -354,7 +339,7 @@ @SuppressWarnings("unused") public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph(); + StructuredGraph graph = newmultiarrayNode.graph(); int rank = newmultiarrayNode.dimensionCount(); ValueNode[] dims = new ValueNode[rank]; for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Mon May 13 17:11:31 2013 +0200 @@ -103,7 +103,7 @@ newEntryState[i] = originalState.getEntry(i); } VirtualObjectNode newVirtual = originalVirtual.duplicate(); - tool.createVirtualObject(newVirtual, newEntryState, 0); + tool.createVirtualObject(newVirtual, newEntryState, null); tool.replaceWithVirtual(newVirtual); } } else { @@ -123,18 +123,9 @@ final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; for (int i = 0; i < fields.length; i++) { state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); + tool.addNode(loads[i]); } - - final StructuredGraph structuredGraph = (StructuredGraph) graph(); - tool.customAction(new Runnable() { - - public void run() { - for (LoadFieldNode load : loads) { - structuredGraph.addBeforeFixed(ObjectCloneNode.this, structuredGraph.add(load)); - } - } - }); - tool.createVirtualObject(newVirtual, state, 0); + tool.createVirtualObject(newVirtual, state, null); tool.replaceWithVirtual(newVirtual); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import java.lang.reflect.*; @@ -54,7 +54,7 @@ int instanceSize = layoutHelper; Pointer memory = NewObjectSnippets.allocate(instanceSize); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); + Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false); memory = Word.fromObject(result); for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { @@ -72,7 +72,7 @@ Pointer memory = NewObjectSnippets.allocate(sizeInBytes); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); + Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false); memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import com.oracle.graal.api.replacements.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,100 @@ +/* + * 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.hotspot.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.nodes.*; + +public class ReflectionGetCallerClassNode extends MacroNode implements Canonicalizable, Lowerable { + + public ReflectionGetCallerClassNode(Invoke invoke) { + super(invoke); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + ConstantNode callerClassNode = getCallerClassNode(tool.runtime()); + if (callerClassNode != null) { + return callerClassNode; + } + return this; + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + ConstantNode callerClassNode = getCallerClassNode(tool.getRuntime()); + + if (callerClassNode != null) { + graph().replaceFixedWithFloating(this, callerClassNode); + } else { + graph().replaceFixedWithFixed(this, createInvoke()); + } + } + + /** + * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by + * walking the the stack. + * + * @param runtime + * @return ConstantNode of the caller class, or null + */ + private ConstantNode getCallerClassNode(MetaAccessProvider runtime) { + if (!GraalOptions.IntrinsifyReflectionMethods) { + return null; + } + + // Walk back up the frame states to find the caller at the required depth. + FrameState state = stateAfter(); + + // Cf. JVM_GetCallerClass + // NOTE: Start the loop at depth 1 because the current frame state does + // not include the Reflection.getCallerClass() frame. + for (int n = 1; state != null; state = state.outerFrameState(), n++) { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.method(); + switch (n) { + case 0: + throw GraalInternalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame"); + case 1: + // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass). + if (!method.isCallerSensitive()) { + return null; // bail-out; let JVM_GetCallerClass do the work + } + break; + default: + if (!method.ignoredBySecurityStackWalk()) { + // We have reached the desired frame; return the holder class. + HotSpotResolvedObjectType callerClass = (HotSpotResolvedObjectType) method.getDeclaringClass(); + return ConstantNode.forObject(callerClass.mirror(), runtime, graph()); + } + break; + } + } + return null; // bail-out; let JVM_GetCallerClass do the work + } + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.spi.MacroSubstitution; + +/** + * Substitutions for {@link sun.reflect.Reflection} methods. + */ +@ClassSubstitution(sun.reflect.Reflection.class) +public class ReflectionSubstitutions { + + @MacroSubstitution(macro = ReflectionGetCallerClassNode.class, optional = true) + public static native Class getCallerClass(); + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.hotspot.nodes.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import java.util.*; @@ -33,16 +33,19 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; +//JaCoCo Exclude + /** * Utilities and common code paths used by the type check snippets. */ public class TypeCheckSnippetUtils { - public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); + public static final LocationIdentity TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); static boolean checkSecondarySubType(Word t, Word s) { // if (S.cache == T) return true diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.replacements.SnippetTemplate.*; import com.oracle.graal.api.code.*; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CRuntimeStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; + +/** + * Base class for a stub that saves registers around a C runtime call. + */ +public abstract class CRuntimeStub extends SnippetStub { + + public CRuntimeStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Override + protected Arguments makeArguments(SnippetInfo stub) { + Arguments args = new Arguments(stub); + for (int i = 0; i < stub.getParameterCount(); i++) { + args.add(stub.getParameterName(i), null); + } + return args; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateNullPointerExceptionStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateNullPointerExceptionStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.*; +import com.oracle.graal.graph.Node.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called to create a {@link NullPointerException}. + */ +public class CreateNullPointerExceptionStub extends CRuntimeStub { + + public CreateNullPointerExceptionStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static Object createNullPointerException() { + createNullPointerExceptionC(CREATE_NULL_POINTER_EXCEPTION_C, thread()); + StubUtil.handlePendingException(true); + return StubUtil.verifyObject(getAndClearObjectResult(thread())); + } + + public static final Descriptor CREATE_NULL_POINTER_EXCEPTION_C = StubUtil.descriptorFor(CreateNullPointerExceptionStub.class, "createNullPointerExceptionC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void createNullPointerExceptionC(@ConstantNodeParameter Descriptor createNullPointerExceptionC, Word thread); + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateOutOfBoundsExceptionStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/CreateOutOfBoundsExceptionStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.*; +import com.oracle.graal.graph.Node.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called to create a {@link ArrayIndexOutOfBoundsException}. + */ +public class CreateOutOfBoundsExceptionStub extends CRuntimeStub { + + public CreateOutOfBoundsExceptionStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static Object createOutOfBoundsException(int index) { + createOutOfBoundsExceptionC(CREATE_OUT_OF_BOUNDS_C, thread(), index); + StubUtil.handlePendingException(true); + return StubUtil.verifyObject(getAndClearObjectResult(thread())); + } + + public static final Descriptor CREATE_OUT_OF_BOUNDS_C = StubUtil.descriptorFor(CreateOutOfBoundsExceptionStub.class, "createOutOfBoundsExceptionC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void createOutOfBoundsExceptionC(@ConstantNodeParameter Descriptor createOutOfBoundsExceptionC, Word thread, int index); + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ExceptionHandlerStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.PatchReturnAddressNode.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.word.*; + +/** + * Stub called by the {@linkplain Marks#MARK_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}. + */ +public class ExceptionHandlerStub extends CRuntimeStub { + + public ExceptionHandlerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + /** + * This stub is called 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. + */ + @Override + public boolean preservesRegisters() { + return false; + } + + @Snippet + private static void exceptionHandler(Object exception, Word exceptionPc) { + checkNoExceptionInThread(assertionsEnabled()); + checkExceptionNotNull(assertionsEnabled(), exception); + writeExceptionOop(thread(), exception); + writeExceptionPc(thread(), exceptionPc); + if (logging()) { + StubUtil.printf("handling exception %p (", Word.fromObject(exception).rawValue()); + StubUtil.decipher(Word.fromObject(exception).rawValue()); + StubUtil.printf(") at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue()); + StubUtil.decipher(exceptionPc.rawValue()); + StubUtil.printf(")\n"); + } + + // patch throwing pc into return address so that deoptimization finds the right debug info + patchReturnAddress(exceptionPc); + + Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread()); + + if (logging()) { + StubUtil.printf("handler for exception %p at %p is at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); + StubUtil.decipher(handlerPc.rawValue()); + StubUtil.printf(")\n"); + } + + // patch the return address so that this stub returns to the exception handler + patchReturnAddress(handlerPc); + } + + static void checkNoExceptionInThread(boolean enabled) { + if (enabled) { + Object currentException = readExceptionOop(thread()); + if (currentException != null) { + StubUtil.fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue()); + } + Word currentExceptionPc = readExceptionPc(thread()); + if (currentExceptionPc.notEqual(Word.zero())) { + StubUtil.fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); + } + } + } + + static void checkExceptionNotNull(boolean enabled, Object exception) { + if (enabled && exception == null) { + StubUtil.fatal("exception must not be null"); + } + } + + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logExceptionHandlerStub"); + } + + @Fold + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled || graalRuntime().getConfig().cAssertions; + } + + public static final Descriptor EXCEPTION_HANDLER_FOR_PC = StubUtil.descriptorFor(ExceptionHandlerStub.class, "exceptionHandlerForPc", false); + + @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForPc(@ConstantNodeParameter Descriptor exceptionHandlerForPc, Word thread); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogObjectStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link Log}. + */ +public class LogObjectStub extends CRuntimeStub { + + public LogObjectStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void logObject(Object object, int flags) { + logObjectC(LOG_OBJECT_C, thread(), object, flags); + } + + public static final Descriptor LOG_OBJECT_C = StubUtil.descriptorFor(LogObjectStub.class, "logObjectC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void logObjectC(@ConstantNodeParameter Descriptor logObjectC, Word thread, Object object, int flags); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrimitiveStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link Log}. + */ +public class LogPrimitiveStub extends CRuntimeStub { + + public LogPrimitiveStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void logPrimitive(char typeChar, long value, boolean newline) { + logPrimitivefC(LOG_PRIMITIVE_C, thread(), typeChar, value, newline); + } + + public static final Descriptor LOG_PRIMITIVE_C = StubUtil.descriptorFor(LogPrimitiveStub.class, "logPrimitivefC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void logPrimitivefC(@ConstantNodeParameter Descriptor logPrimitivefC, Word thread, char typeChar, long value, boolean newline); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/LogPrintfStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link Log}. + */ +public class LogPrintfStub extends CRuntimeStub { + + public LogPrintfStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void logPrintf(String format, long v1, long v2, long v3) { + logPrintfC(LOG_PRINTF_C, thread(), format, v1, v2, v3); + } + + public static final Descriptor LOG_PRINTF_C = StubUtil.descriptorFor(LogPrintfStub.class, "logPrintfC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void logPrintfC(@ConstantNodeParameter Descriptor logPrintfC, Word thread, String format, long v1, long v2, long v3); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorEnterStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorEnterStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link MonitorEnterStubCall}. + */ +public class MonitorEnterStub extends CRuntimeStub { + + public MonitorEnterStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void monitorenter(Object object, Word lock) { + monitorenterC(MONITORENTER_C, thread(), object, lock); + StubUtil.handlePendingException(false); + } + + public static final Descriptor MONITORENTER_C = StubUtil.descriptorFor(MonitorEnterStub.class, "monitorenterC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void monitorenterC(@ConstantNodeParameter Descriptor monitorenterC, Word thread, Object object, Word lock); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorExitStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/MonitorExitStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link MonitorExitStubCall}. + */ +public class MonitorExitStub extends CRuntimeStub { + + public MonitorExitStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void monitorexit(Object object, Word lock) { + monitorexitC(MONITOREXIT_C, thread(), object, lock); + } + + public static final Descriptor MONITOREXIT_C = StubUtil.descriptorFor(MonitorExitStub.class, "monitorexitC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void monitorexitC(@ConstantNodeParameter Descriptor monitorexitC, Word thread, Object object, Word lock); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon May 13 17:11:31 2013 +0200 @@ -22,46 +22,62 @@ */ package com.oracle.graal.hotspot.stubs; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.replacements.SnippetTemplate.Arguments; import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; /** * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is - * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. - * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ - * runtime for to complete the allocation. + * called via {@link NewArrayStubCall} from the {@linkplain NewObjectSnippets inline} allocation + * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it + * calls out to the HotSpot C++ runtime to complete the allocation. */ -public class NewArrayStub extends Stub { +public class NewArrayStub extends SnippetStub { public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage, "newArray"); + super(runtime, replacements, target, linkage); } @Override protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we + // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since + // the int[] class will never be unloaded. + Constant intArrayHub = intArrayType.klass(); + intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null); + Arguments args = new Arguments(stub); args.add("hub", null); args.add("length", null); - args.addConst("intArrayHub", intArrayType.klass()); - args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub")); + args.addConst("intArrayHub", intArrayHub); return args; } + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logNewArrayStub"); + } + /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). @@ -69,30 +85,50 @@ * @param hub the hub of the object to be allocated * @param length the length of the array * @param intArrayHub the hub for {@code int[].class} - * @param log specifies if logging is enabled */ @Snippet - private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { + private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub) { int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize); - log(log, "newArray: element kind %d\n", elementKind); - log(log, "newArray: array length %d\n", length); - log(log, "newArray: array size %d\n", sizeInBytes); - log(log, "newArray: hub=%p\n", hub); + if (logging()) { + StubUtil.printf("newArray: element kind %d\n", elementKind); + StubUtil.printf("newArray: array length %d\n", length); + StubUtil.printf("newArray: array size %d\n", sizeInBytes); + StubUtil.printf("newArray: hub=%p\n", hub.rawValue()); + } // check that array length is small enough for fast path. if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, log); + Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { - log(log, "newArray: allocated new array at %p\n", memory); + if (logging()) { + StubUtil.printf("newArray: allocated new array at %p\n", memory.rawValue()); + } formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord()), true); - return verifyOop(memory.toObject()); + return StubUtil.verifyObject(memory.toObject()); } } - log(log, "newArray: calling new_array_slow", 0L); - return verifyOop(NewArraySlowStubCall.call(hub, length)); + if (logging()) { + StubUtil.printf("newArray: calling new_array_c\n"); + } + + newArrayC(NEW_ARRAY_C, thread(), hub, length); + + if (clearPendingException(thread())) { + if (logging()) { + StubUtil.printf("newArray: deoptimizing to caller\n"); + } + getAndClearObjectResult(thread()); + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + return StubUtil.verifyObject(getAndClearObjectResult(thread())); } + + public static final Descriptor NEW_ARRAY_C = StubUtil.descriptorFor(NewArrayStub.class, "newArrayC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int length); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon May 13 17:11:31 2013 +0200 @@ -22,12 +22,18 @@ */ package com.oracle.graal.hotspot.stubs; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -42,27 +48,37 @@ /** * Stub implementing the fast path for TLAB refill during instance class allocation. This stub is - * called from the {@linkplain NewObjectSnippets inline} allocation code when TLAB allocation fails. - * If this stub fails to refill the TLAB or allocate the object, it calls out to the HotSpot C++ - * runtime for to complete the allocation. + * called via {@link NewInstanceStubCall} from the {@linkplain NewObjectSnippets inline} allocation + * code when TLAB allocation fails. If this stub fails to refill the TLAB or allocate the object, it + * calls out to the HotSpot C++ runtime for to complete the allocation. */ -public class NewInstanceStub extends Stub { +public class NewInstanceStub extends SnippetStub { public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { - super(runtime, replacements, target, linkage, "newInstance"); + super(runtime, replacements, target, linkage); } @Override protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + // RuntimeStub cannot (currently) support oops or metadata embedded in the code so we + // convert the hub (i.e., Klass*) for int[] to be a naked word. This should be safe since + // the int[] class will never be unloaded. + Constant intArrayHub = intArrayType.klass(); + intArrayHub = Constant.forIntegerKind(graalRuntime().getTarget().wordKind, intArrayHub.asLong(), null); + Arguments args = new Arguments(stub); args.add("hub", null); - args.addConst("intArrayHub", intArrayType.klass()); - args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub")); + args.addConst("intArrayHub", intArrayHub); return args; } + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logNewInstanceStub"); + } + /** * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to * -XX:-UseTLAB). @@ -71,22 +87,36 @@ * @param intArrayHub the hub for {@code int[].class} */ @Snippet - private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { + private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub) { int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { - Word memory = refillAllocate(intArrayHub, sizeInBytes, log); + Word memory = refillAllocate(intArrayHub, sizeInBytes, logging()); if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); initializeObjectHeader(memory, prototypeMarkWord, hub); for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { memory.writeWord(offset, Word.zero(), ANY_LOCATION); } - return verifyOop(memory.toObject()); + return StubUtil.verifyObject(memory.toObject()); } } } - return verifyOop(NewInstanceSlowStubCall.call(hub)); + + if (logging()) { + StubUtil.printf("newInstance: calling new_instance_c\n"); + } + + newInstanceC(NEW_INSTANCE_C, thread(), hub); + + if (clearPendingException(thread())) { + if (logging()) { + StubUtil.printf("newInstance: deoptimizing to caller\n"); + } + getAndClearObjectResult(thread()); + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + return StubUtil.verifyObject(getAndClearObjectResult(thread())); } /** @@ -112,10 +142,12 @@ // calculate amount of free space Word tlabFreeSpaceInBytes = end.subtract(top); - log(log, "refillTLAB: thread=%p\n", thread); - log(log, "refillTLAB: top=%p\n", top); - log(log, "refillTLAB: end=%p\n", end); - log(log, "refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes); + if (log) { + StubUtil.printf("refillTLAB: thread=%p\n", thread.rawValue()); + StubUtil.printf("refillTLAB: top=%p\n", top.rawValue()); + StubUtil.printf("refillTLAB: end=%p\n", end.rawValue()); + StubUtil.printf("refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes.rawValue()); + } Word tlabFreeSpaceInWords = tlabFreeSpaceInBytes.unsignedShiftRight(log2WordSize()); @@ -126,10 +158,14 @@ if (tlabStats()) { // increment number of refills thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION); - log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); + if (log) { + StubUtil.printf("thread: %p -- number_of_refills %d\n", thread.rawValue(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); + } // accumulate wastage Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords); - log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage); + if (log) { + StubUtil.printf("thread: %p -- accumulated wastage %d\n", thread.rawValue(), wastage.rawValue()); + } thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION); } @@ -165,7 +201,9 @@ // Retain TLAB Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement()); thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION); - log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit); + if (log) { + StubUtil.printf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.rawValue()); + } if (tlabStats()) { thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION); @@ -208,4 +246,9 @@ private static boolean forceSlowPath() { return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath"); } + + public static final Descriptor NEW_INSTANCE_C = StubUtil.descriptorFor(NewInstanceStub.class, "newInstanceC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newInstanceC(@ConstantNodeParameter Descriptor newInstanceC, Word thread, Word hub); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewMultiArrayStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link NewMultiArrayStubCall}. + */ +public class NewMultiArrayStub extends CRuntimeStub { + + public NewMultiArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static Object newMultiArray(Word hub, int rank, Word dims) { + newMultiArrayC(NEW_MULTI_ARRAY_C, thread(), hub, rank, dims); + StubUtil.handlePendingException(true); + return getAndClearObjectResult(thread()); + } + + public static final Descriptor NEW_MULTI_ARRAY_C = StubUtil.descriptorFor(NewMultiArrayStub.class, "newMultiArrayC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void newMultiArrayC(@ConstantNodeParameter Descriptor newArrayC, Word thread, Word hub, int rank, Word dims); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/OSRMigrationEndStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link OSRStartNode}. + */ +public class OSRMigrationEndStub extends CRuntimeStub { + + public OSRMigrationEndStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void osrMigrationEnd(Word buffer) { + osrMigrationEndC(OSR_MIGRATION_END_C, buffer); + } + + public static final Descriptor OSR_MIGRATION_END_C = StubUtil.descriptorFor(OSRMigrationEndStub.class, "osrMigrationEndC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void osrMigrationEndC(@ConstantNodeParameter Descriptor osrMigrationEndC, Word buffer); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RegisterFinalizerStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RegisterFinalizerStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link RegisterFinalizerNode}. + */ +public class RegisterFinalizerStub extends CRuntimeStub { + + public RegisterFinalizerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void registerFinalizer(Object object) { + registerFinalizerC(REGISTER_FINALIZER_C, thread(), object); + StubUtil.handlePendingException(false); + } + + public static final Descriptor REGISTER_FINALIZER_C = StubUtil.descriptorFor(RegisterFinalizerStub.class, "registerFinalizerC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void registerFinalizerC(@ConstantNodeParameter Descriptor registerFinalizerC, Word thread, Object object); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/RuntimeCallStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.api.meta.MetaUtil.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; +import com.oracle.graal.word.phases.*; + +/** + * Base class for a stub that calls into a HotSpot C/C++ runtime function using the native + * {@link CallingConvention}. + */ +public class RuntimeCallStub extends Stub { + + /** + * The target of the call. + */ + private final HotSpotRuntimeCallTarget target; + + /** + * Specifies if the JavaThread value for the current thread is to be prepended to the arguments + * for the call to {@link #target}. + */ + protected final boolean prependThread; + + /** + * Creates a stub for a call to code at a given address. + * + * @param address the address of the code to call + * @param sig the signature of the call to this stub + * @param prependThread true if the JavaThread value for the current thread is to be prepended + * to the arguments for the call to {@code address} + * @param regConfig used to get the calling convention for the call to this stub from Graal + * compiled Java code as well as the calling convention for the call to + * {@code address} + * @param vm the Java to HotSpot C/C++ runtime interface + */ + public RuntimeCallStub(long address, Descriptor sig, boolean prependThread, HotSpotRuntime runtime, Replacements replacements, RegisterConfig regConfig, CompilerToVM vm) { + super(runtime, replacements, new HotSpotRuntimeCallTarget(sig, 0L, false, createCallingConvention(runtime, regConfig, sig), vm)); + this.prependThread = prependThread; + Class[] targetParameterTypes = createTargetParameters(sig); + Descriptor targetSig = new Descriptor(sig.getName() + ":C", sig.hasSideEffect(), sig.getResultType(), targetParameterTypes); + CallingConvention targetCc = createCallingConvention(runtime, regConfig, targetSig); + target = new HotSpotRuntimeCallTarget(targetSig, address, true, targetCc, vm); + } + + /** + * Gets the linkage information for the runtime call. + */ + public HotSpotRuntimeCallTarget getTargetLinkage() { + return target; + } + + private static CallingConvention createCallingConvention(HotSpotRuntime runtime, RegisterConfig regConfig, Descriptor d) { + Class[] argumentTypes = d.getArgumentTypes(); + JavaType[] parameterTypes = new JavaType[argumentTypes.length]; + for (int i = 0; i < parameterTypes.length; ++i) { + parameterTypes[i] = runtime.lookupJavaType(argumentTypes[i]); + } + TargetDescription target = graalRuntime().getTarget(); + JavaType returnType = runtime.lookupJavaType(d.getResultType()); + return regConfig.getCallingConvention(Type.NativeCall, returnType, parameterTypes, target, false); + } + + private Class[] createTargetParameters(Descriptor sig) { + Class[] parameters = sig.getArgumentTypes(); + if (prependThread) { + Class[] newParameters = new Class[parameters.length + 1]; + System.arraycopy(parameters, 0, newParameters, 1, parameters.length); + newParameters[0] = Word.class; + return newParameters; + } + return parameters; + } + + @Override + protected ResolvedJavaMethod getInstalledCodeOwner() { + return null; + } + + @Override + protected Object debugScopeContext() { + return new JavaMethod() { + + public Signature getSignature() { + Descriptor d = linkage.descriptor; + Class[] arguments = d.getArgumentTypes(); + JavaType[] parameters = new JavaType[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + parameters[i] = runtime.lookupJavaType(arguments[i]); + } + return new HotSpotSignature(runtime.lookupJavaType(d.getResultType()), parameters); + } + + public String getName() { + return linkage.descriptor.getName(); + } + + public JavaType getDeclaringClass() { + return runtime.lookupJavaType(RuntimeCallStub.class); + } + + @Override + public String toString() { + return format("HotSpotStub<%n(%p)>", this); + } + }; + } + + @Override + protected StructuredGraph getGraph() { + Class[] args = linkage.getDescriptor().getArgumentTypes(); + LocalNode[] locals = new LocalNode[args.length]; + + StructuredGraph graph = new StructuredGraph(toString(), null); + StubStartNode start = graph.add(new StubStartNode(this)); + graph.replaceFixed(graph.start(), start); + + ResolvedJavaType accessingClass = runtime.lookupJavaType(getClass()); + for (int i = 0; i < args.length; i++) { + JavaType type = runtime.lookupJavaType(args[i]).resolve(accessingClass); + Kind kind = type.getKind().getStackKind(); + Stamp stamp; + if (kind == Kind.Object) { + stamp = StampFactory.declared((ResolvedJavaType) type); + } else { + stamp = StampFactory.forKind(kind); + } + LocalNode local = graph.unique(new LocalNode(i, stamp)); + locals[i] = local; + } + + // Create target call + CRuntimeCall call = createTargetCall(locals, graph, start); + + // Create call to handlePendingException + ResolvedJavaMethod hpeMethod = resolveMethod(StubUtil.class, "handlePendingException", boolean.class); + JavaType returnType = hpeMethod.getSignature().getReturnType(null); + ValueNode[] hpeArgs = {ConstantNode.forBoolean(linkage.getCallingConvention().getReturn().getKind() == Kind.Object, graph)}; + MethodCallTargetNode hpeTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, hpeMethod, hpeArgs, returnType)); + InvokeNode hpeInvoke = graph.add(new InvokeNode(hpeTarget, FrameState.UNKNOWN_BCI)); + List emptyStack = Collections.emptyList(); + hpeInvoke.setStateAfter(graph.add(new FrameState(null, FrameState.INVALID_FRAMESTATE_BCI, new ValueNode[0], emptyStack, new ValueNode[0], false, false))); + graph.addAfterFixed(call, hpeInvoke); + + // Create return node + ReturnNode ret = graph.add(new ReturnNode(linkage.descriptor.getResultType() == void.class ? null : call)); + graph.addAfterFixed(hpeInvoke, ret); + + if (Debug.isDumpEnabled()) { + Debug.dump(graph, "Initial stub graph"); + } + + // Inline call to handlePendingException + inline(hpeInvoke); + + if (Debug.isDumpEnabled()) { + Debug.dump(graph, "Stub graph before compilation"); + } + + return graph; + } + + private CRuntimeCall createTargetCall(LocalNode[] locals, StructuredGraph graph, StubStartNode start) { + CRuntimeCall call; + ValueNode[] targetArguments; + if (prependThread) { + ReadRegisterNode thread = graph.add(new ReadRegisterNode(runtime.threadRegister(), true, false)); + graph.addAfterFixed(start, thread); + targetArguments = new ValueNode[1 + locals.length]; + targetArguments[0] = thread; + System.arraycopy(locals, 0, targetArguments, 1, locals.length); + call = graph.add(new CRuntimeCall(target.descriptor, targetArguments)); + graph.addAfterFixed(thread, call); + } else { + targetArguments = new ValueNode[locals.length]; + System.arraycopy(locals, 0, targetArguments, 0, locals.length); + call = graph.add(new CRuntimeCall(target.descriptor, targetArguments)); + graph.addAfterFixed(start, call); + } + return call; + } + + private void inline(InvokeNode invoke) { + StructuredGraph graph = invoke.graph(); + ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); + ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget()); + StructuredGraph hpeGraph = repl.makeGraph(method, null, null); + InliningUtil.inline(invoke, hpeGraph, false); + new NodeIntrinsificationPhase(runtime).apply(graph); + new WordTypeRewriterPhase(runtime, wordKind()).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + } + + private ResolvedJavaMethod resolveMethod(Class declaringClass, String name, Class... parameterTypes) { + try { + return runtime.lookupJavaMethod(declaringClass.getDeclaredMethod(name, parameterTypes)); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.api.meta.MetaUtil.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; + +/** + * Base class for a stub defined by a snippet. + */ +public abstract class SnippetStub extends Stub implements Snippets { + + static class Template extends AbstractTemplates { + + Template(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, Class declaringClass) { + super(runtime, replacements, target); + this.info = snippet(declaringClass, null); + } + + /** + * Info for the method implementing the stub. + */ + protected final SnippetInfo info; + + protected StructuredGraph getGraph(Arguments args) { + SnippetTemplate template = template(args); + return template.copySpecializedGraph(); + } + } + + protected final Template snippet; + + /** + * Creates a new snippet stub. + * + * @param linkage linkage details for a call to the stub + */ + public SnippetStub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, linkage); + this.snippet = new Template(runtime, replacements, target, getClass()); + } + + @Override + protected StructuredGraph getGraph() { + return snippet.getGraph(makeArguments(snippet.info)); + } + + /** + * Adds the {@linkplain ConstantParameter constant} arguments of this stub. + */ + protected abstract Arguments makeArguments(SnippetInfo stub); + + @Override + protected Object debugScopeContext() { + return getInstalledCodeOwner(); + } + + @Override + public ResolvedJavaMethod getInstalledCodeOwner() { + return snippet.info.getMethod(); + } + + @Override + public String toString() { + return "Stub<" + format("%h.%n", getInstalledCodeOwner()) + ">"; + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Mon May 13 17:11:31 2013 +0200 @@ -22,51 +22,39 @@ */ package com.oracle.graal.hotspot.stubs; -import static com.oracle.graal.hotspot.nodes.CStringNode.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import java.util.*; import java.util.concurrent.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.graph.*; 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.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.replacements.*; -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; -import com.oracle.graal.word.*; + +//JaCoCo Exclude /** - * Base class for implementing some low level code providing the out-of-line slow path for a - * snippet. A concrete stub is defined a subclass of this class. - *

    - * Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s - * purely for convenience (e.g., can re-use the {@link ReplacementsImpl}). + * Base class for implementing some low level code providing the out-of-line slow path for a snippet + * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java + * method. */ -public abstract class Stub extends AbstractTemplates implements Snippets { +public abstract class Stub { /** - * The method implementing the stub. - */ - protected final SnippetInfo stubInfo; - - /** - * The linkage information for the stub. + * The linkage information for a call to this stub from compiled code. */ protected final HotSpotRuntimeCallTarget linkage; @@ -76,139 +64,125 @@ protected InstalledCode code; /** - * The registers defined by this stub. + * The registers destroyed by this stub. */ - private Set definedRegisters; + private Set destroyedRegisters; - public void initDefinedRegisters(Set registers) { + public void initDestroyedRegisters(Set registers) { assert registers != null; - assert definedRegisters == null : "cannot redefine"; - definedRegisters = registers; - } - - public Set getDefinedRegisters() { - assert definedRegisters != null : "not yet initialized"; - return definedRegisters; + assert destroyedRegisters == null || registers.equals(destroyedRegisters) : "cannot redefine"; + destroyedRegisters = registers; } /** - * Creates a new stub container.. + * Gets the registers defined by this stub. These are the temporaries of this stub and must thus + * be caller saved by a callers of this stub. + */ + public Set getDestroyedRegisters() { + assert destroyedRegisters != null : "not yet initialized"; + return destroyedRegisters; + } + + /** + * Determines if this stub preserves all registers apart from those it + * {@linkplain #getDestroyedRegisters() destroys}. + */ + public boolean preservesRegisters() { + return true; + } + + protected final HotSpotRuntime runtime; + + protected final Replacements replacements; + + /** + * Creates a new stub. * * @param linkage linkage details for a call to the stub */ - public Stub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage, String methodName) { - super(runtime, replacements, target); - this.stubInfo = snippet(getClass(), methodName); + public Stub(HotSpotRuntime runtime, Replacements replacements, HotSpotRuntimeCallTarget linkage) { this.linkage = linkage; + this.runtime = runtime; + this.replacements = replacements; + } + /** + * Gets the linkage for a call to this stub from compiled code. + */ + public HotSpotRuntimeCallTarget getLinkage() { + return linkage; } /** - * Adds the {@linkplain ConstantParameter constant} arguments of this stub. + * Gets the graph that from which the code for this stub will be compiled. */ - protected abstract Arguments makeArguments(SnippetInfo stub); + protected abstract StructuredGraph getGraph(); - protected HotSpotRuntime runtime() { - return (HotSpotRuntime) runtime; + @Override + public String toString() { + return "Stub<" + linkage.getDescriptor() + ">"; } /** - * Gets the method implementing this stub. + * Gets the method the stub's code will be {@linkplain InstalledCode#getMethod() associated} + * with once installed. This may be null. */ - public ResolvedJavaMethod getMethod() { - return stubInfo.getMethod(); - } + protected abstract ResolvedJavaMethod getInstalledCodeOwner(); - public HotSpotRuntimeCallTarget getLinkage() { - return linkage; - } + /** + * Gets a context object for the debug scope created when producing the code for this stub. + */ + protected abstract Object debugScopeContext(); /** * Gets the code for this stub, compiling it first if necessary. */ public synchronized InstalledCode getCode(final Backend backend) { if (code == null) { - Debug.sandbox("CompilingStub", new Object[]{runtime(), getMethod()}, DebugScope.getConfig(), new Runnable() { + Debug.sandbox("CompilingStub", new Object[]{runtime, debugScopeContext()}, DebugScope.getConfig(), new Runnable() { @Override public void run() { - Arguments args = makeArguments(stubInfo); - SnippetTemplate template = template(args); - StructuredGraph graph = template.copySpecializedGraph(); + final StructuredGraph graph = getGraph(); + if (!(graph.start() instanceof StubStartNode)) { + StubStartNode newStart = graph.add(new StubStartNode(Stub.this)); + newStart.setStateAfter(graph.start().stateAfter()); + graph.replaceFixed(graph.start(), newStart); + } PhasePlan phasePlan = new PhasePlan(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); - final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan, + CallingConvention cc = linkage.getCallingConvention(); + final CompilationResult compResult = GraalCompiler.compileGraph(graph, cc, getInstalledCodeOwner(), runtime, replacements, backend, runtime.getTarget(), null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog()); - assert definedRegisters != null; + assert destroyedRegisters != null; code = Debug.scope("CodeInstall", new Callable() { @Override public InstalledCode call() { - InstalledCode installedCode = runtime().addMethod(getMethod(), compResult); - assert installedCode != null : "error installing stub " + getMethod(); + Stub stub = Stub.this; + HotSpotInstalledCode installedCode = new HotSpotInstalledCode(stub); + HotSpotCompilationResult hsCompResult = new HotSpotCompilationResult(stub, compResult); + CodeInstallResult result = graalRuntime().getCompilerToVM().installCode(hsCompResult, installedCode, null); + if (result != CodeInstallResult.OK) { + throw new GraalInternalError("Error installing stub %s: %s", Stub.this, result); + } if (Debug.isDumpEnabled()) { Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } + // TTY.println(stub.toString()); + // TTY.println(runtime.disassemble(installedCode)); return installedCode; } }); } }); - assert code != null : "error installing stub " + getMethod(); + assert code != null : "error installing stub " + this; } return code; } - - static void log(boolean enabled, String format, long value) { - if (enabled) { - printf(format, value); - } - } - - static void log(boolean enabled, String format, WordBase value) { - if (enabled) { - printf(format, value.rawValue()); - } - } - - static void log(boolean enabled, String format, Word v1, long v2) { - if (enabled) { - printf(format, v1.rawValue(), v2); - } - } - - static void log(boolean enabled, String format, Word v1, Word v2) { - if (enabled) { - printf(format, v1.rawValue(), v2.rawValue()); - } - } - - public static final Descriptor STUB_PRINTF = new Descriptor("stubPrintf", false, void.class, Word.class, long.class, long.class, long.class); - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void printf(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3); - - /** - * Prints a formatted string to the log stream. - * - * @param format a C style printf format value that can contain at most one conversion specifier - * (i.e., a sequence of characters starting with '%'). - * @param value the value associated with the conversion specifier - */ - public static void printf(String format, long value) { - printf(STUB_PRINTF, cstring(format), value, 0L, 0L); - } - - public static void printf(String format, long v1, long v2) { - printf(STUB_PRINTF, cstring(format), v1, v2, 0L); - } - - public static void printf(String format, long v1, long v2, long v3) { - printf(STUB_PRINTF, cstring(format), v1, v2, v3); - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,243 @@ +/* + * 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.hotspot.stubs; + +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.nodes.CStringNode.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.word.Word.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.word.*; + +//JaCoCo Exclude + +/** + * A collection of methods used in {@link Stub}s. + */ +public class StubUtil { + + public static final Descriptor VM_MESSAGE_C = descriptorFor(StubUtil.class, "vmMessageC", false); + + /** + * Looks for a {@link CRuntimeCall} node intrinsic named {@code name} in {@code stubClass} and + * returns a {@link Descriptor} based on its signature and the value of {@code hasSideEffect}. + */ + public static Descriptor descriptorFor(Class stubClass, String name, boolean hasSideEffect) { + Method found = null; + for (Method method : stubClass.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { + if (method.getAnnotation(NodeIntrinsic.class).value() == CRuntimeCall.class) { + assert found == null : "found more than one C runtime call named " + name + " in " + stubClass; + assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == Descriptor.class : "first parameter of C runtime call '" + name + "' in " + stubClass + + " must be of type " + Descriptor.class.getSimpleName(); + found = method; + } + } + } + assert found != null : "could not find C runtime call named " + name + " in " + stubClass; + List> paramList = Arrays.asList(found.getParameterTypes()); + Class[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]); + return new Descriptor(name, hasSideEffect, found.getReturnType(), cCallTypes); + } + + public static void handlePendingException(boolean isObjectResult) { + if (clearPendingException(thread())) { + if (isObjectResult) { + getAndClearObjectResult(thread()); + } + DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); + } + } + + @NodeIntrinsic(CRuntimeCall.class) + private static native void vmMessageC(@ConstantNodeParameter Descriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param message a message string + */ + public static void printf(String message) { + vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param value the value associated with the first conversion specifier in {@code format} + */ + public static void printf(String format, long value) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object + * constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + */ + public static void printf(String format, long v1, long v2) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L); + } + + /** + * Prints a message to the log stream. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + * @param v3 the value associated with the third conversion specifier in {@code format} + */ + public static void printf(String format, long v1, long v2, long v3) { + vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3); + } + + /** + * Analyzes a given value and prints information about it to the log stream. + */ + public static void decipher(long value) { + vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param message an error message + */ + public static void fatal(String message) { + vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param value the value associated with the first conversion specifier in {@code format} + */ + public static void fatal(String format, long value) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + */ + public static void fatal(String format, long v1, long v2) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); + } + + /** + * Exits the VM with a given error message. + *

    + * Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an + * object constant in a RuntimeStub. + * + * @param format a C style printf format value + * @param v1 the value associated with the first conversion specifier in {@code format} + * @param v2 the value associated with the second conversion specifier in {@code format} + * @param v3 the value associated with the third conversion specifier in {@code format} + */ + public static void fatal(String format, long v1, long v2, long v3) { + vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); + } + + /** + * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled. + */ + public static Object verifyObject(Object object) { + if (verifyOops()) { + Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress()); + verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1); + + Pointer oop = Word.fromObject(object); + if (object != null) { + // make sure object is 'reasonable' + if (!oop.and(unsigned(verifyOopMask())).equal(unsigned(verifyOopBits()))) { + fatal("oop not in heap: %p", oop.rawValue()); + } + + Word klass = oop.readWord(hubOffset()); + if (klass.equal(Word.zero())) { + fatal("klass for oop %p is null", oop.rawValue()); + } + } + } + return object; + } + + @Fold + private static long verifyOopCounterAddress() { + return config().verifyOopCounterAddress; + } + + @Fold + private static long verifyOopMask() { + return config().verifyOopMask; + } + + @Fold + private static long verifyOopBits() { + return config().verifyOopBits; + } + + @Fold + private static int hubOffset() { + return config().hubOffset; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ThreadIsInterruptedStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link ThreadIsInterruptedStubCall}. + */ +public class ThreadIsInterruptedStub extends CRuntimeStub { + + public ThreadIsInterruptedStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static boolean threadIsInterrupted(Thread receiverThread, boolean clearIsInterrupted) { + boolean result = threadIsInterruptedC(THREAD_IS_INTERRUPTED_C, thread(), receiverThread, clearIsInterrupted); + StubUtil.handlePendingException(false); + return result; + } + + public static final Descriptor THREAD_IS_INTERRUPTED_C = StubUtil.descriptorFor(ThreadIsInterruptedStub.class, "threadIsInterruptedC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native boolean threadIsInterruptedC(@ConstantNodeParameter Descriptor threadIsInterruptedC, Word thread, Thread receiverThread, boolean clearIsInterrupted); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UnwindExceptionToCallerStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerInCallerNode.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.word.*; + +/** + * Stub called by an {@link UnwindNode}. This stub executes in the frame of the method throwing an + * exception and completes by jumping to the exception handler in the calling frame. + */ +public class UnwindExceptionToCallerStub extends CRuntimeStub { + + public UnwindExceptionToCallerStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + /** + * The current frame is unwound by this stub. Therefore, it does not need to save any registers + * as HotSpot uses a caller save convention. + */ + @Override + public boolean preservesRegisters() { + return false; + } + + @Snippet + private static void unwindExceptionToCaller(Object exception, Word returnAddress) { + Pointer exceptionOop = Word.fromObject(exception); + if (logging()) { + StubUtil.printf("unwinding exception %p (", exceptionOop.rawValue()); + StubUtil.decipher(exceptionOop.rawValue()); + StubUtil.printf(") at %p (", exceptionOop.rawValue(), returnAddress.rawValue()); + StubUtil.decipher(returnAddress.rawValue()); + StubUtil.printf(")\n"); + } + checkNoExceptionInThread(assertionsEnabled()); + checkExceptionNotNull(assertionsEnabled(), exception); + + Word handlerInCallerPc = exceptionHandlerForReturnAddress(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, thread(), returnAddress); + + if (logging()) { + StubUtil.printf("handler for exception %p at return address %p is at %p (", exceptionOop.rawValue(), returnAddress.rawValue(), handlerInCallerPc.rawValue()); + StubUtil.decipher(handlerInCallerPc.rawValue()); + StubUtil.printf(")\n"); + } + + jumpToExceptionHandlerInCaller(handlerInCallerPc, exception, returnAddress); + } + + @Fold + private static boolean logging() { + return Boolean.getBoolean("graal.logUnwindExceptionToCallerStub"); + } + + @Fold + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean enabled = false; + assert enabled = true; + return enabled || graalRuntime().getConfig().cAssertions; + } + + public static final Descriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = StubUtil.descriptorFor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", false); + + @NodeIntrinsic(value = CRuntimeCall.class, setStampFromReturnType = true) + public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter Descriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VMErrorStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link VMErrorNode}. + */ +public class VMErrorStub extends CRuntimeStub { + + public VMErrorStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void vmError(String where, String format, long value) { + vmErrorC(VM_ERROR_C, thread(), where, format, value); + } + + public static final Descriptor VM_ERROR_C = StubUtil.descriptorFor(VMErrorStub.class, "vmErrorC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void vmErrorC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, String where, String format, long value); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/VerifyOopStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; + +/** + * Stub called from {@link VerifyOopStubCall}. + */ +public class VerifyOopStub extends CRuntimeStub { + + public VerifyOopStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static Object verifyOop(Object object) { + return StubUtil.verifyObject(object); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPostStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPostStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link WriteBarrierPostStubCall}. + */ +public class WriteBarrierPostStub extends CRuntimeStub { + + public WriteBarrierPostStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void writeBarrierPost(Object object, Word card) { + writeBarrierPostC(WRITE_BARRIER_POST_C, thread(), object, card); + } + + public static final Descriptor WRITE_BARRIER_POST_C = StubUtil.descriptorFor(WriteBarrierPostStub.class, "writeBarrierPostC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void writeBarrierPostC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, Object object, Word card); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPreStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/WriteBarrierPreStub.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Stub called from {@link WriteBarrierPreStubCall}. + */ +public class WriteBarrierPreStub extends CRuntimeStub { + + public WriteBarrierPreStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage); + } + + @Snippet + private static void writeBarrierPre(Object object) { + writeBarrierPreC(WRITE_BARRIER_PRE_C, thread(), object); + } + + public static final Descriptor WRITE_BARRIER_PRE_C = StubUtil.descriptorFor(WriteBarrierPreStub.class, "writeBarrierPreC", false); + + @NodeIntrinsic(CRuntimeCall.class) + public static native void writeBarrierPreC(@ConstantNodeParameter Descriptor vmErrorC, Word thread, Object object); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Mon May 13 17:11:31 2013 +0200 @@ -253,7 +253,7 @@ } } - public void insertProxies(BeginNode begin) { + public void insertProxies(AbstractBeginNode begin) { for (int i = 0; i < localsSize(); i++) { ValueNode value = localAt(i); if (value != null) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon May 13 17:11:31 2013 +0200 @@ -34,7 +34,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ProfilingInfo.TriState; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; import com.oracle.graal.bytecode.*; @@ -680,11 +679,7 @@ } private void genGoto() { - double probability = profilingInfo.getBranchTakenProbability(bci()); - if (probability < 0) { - probability = 1; - } - appendGoto(createTarget(probability, currentBlock.successors.get(0), frameState)); + appendGoto(createTarget(currentBlock.successors.get(0), frameState)); assert currentBlock.numNormalSuccessors() == 1; } @@ -726,8 +721,8 @@ } condition = currentGraph.unique(condition); - BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); - BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); + AbstractBeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); + AbstractBeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability); append(currentGraph.add(ifNode)); @@ -798,12 +793,7 @@ if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { return null; } else { - ResolvedJavaType uniqueSubtype = type.findUniqueConcreteSubtype(); - if (uniqueSubtype != null) { - return new JavaTypeProfile(profilingInfo.getNullSeen(bci()), 0.0D, new ProfiledType(uniqueSubtype, 1.0D)); - } else { - return profilingInfo.getTypeProfile(bci()); - } + return profilingInfo.getTypeProfile(bci()); } } @@ -812,7 +802,8 @@ JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.apop(); if (type instanceof ResolvedJavaType) { - CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, getProfileForTypeCheck((ResolvedJavaType) type))); + JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type); + CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, profileForTypeCheck, false)); append(checkCast); frameState.apush(checkCast); } else { @@ -837,7 +828,7 @@ void genNewInstance(int cpi) { JavaType type = lookupType(cpi, NEW); if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { - NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true, false)); + NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true)); frameState.apush(append(n)); } else { handleUnresolvedNewInstance(type); @@ -879,7 +870,7 @@ private void genNewPrimitiveArray(int typeCode) { Class clazz = arrayTypeCodeToClass(typeCode); ResolvedJavaType elementType = runtime.lookupJavaType(clazz); - NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true, false)); + NewArrayNode nta = currentGraph.add(new NewArrayNode(elementType, frameState.ipop(), true)); frameState.apush(append(nta)); } @@ -887,7 +878,7 @@ JavaType type = lookupType(cpi, ANEWARRAY); ValueNode length = frameState.ipop(); if (type instanceof ResolvedJavaType) { - NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true, false)); + NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true)); frameState.apush(append(n)); } else { handleUnresolvedNewObjectArray(type, length); @@ -1012,13 +1003,8 @@ private void genGetStatic(JavaField field) { Kind kind = field.getKind(); if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - Constant constantValue = ((ResolvedJavaField) field).readConstantValue(null); - if (constantValue != null) { - frameState.push(constantValue.getKind().getStackKind(), appendConstant(constantValue)); - } else { - LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field)); - appendOptimizedLoadField(kind, load); - } + LoadFieldNode load = currentGraph.add(new LoadFieldNode(null, (ResolvedJavaField) field)); + appendOptimizedLoadField(kind, load); } else { handleUnresolvedLoadField(field, null); } @@ -1165,6 +1151,10 @@ if (graphBuilderConfig.eagerResolving()) { returnType = returnType.resolve(targetMethod.getDeclaringClass()); } + if (invokeKind != InvokeKind.Static && invokeKind != InvokeKind.Special) { + JavaTypeProfile profile = profilingInfo.getTypeProfile(bci()); + args[0] = TypeProfileProxyNode.create(args[0], profile); + } MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType)); createInvokeNode(callTarget, resultType); } @@ -1494,7 +1484,7 @@ BlockPlaceholderNode placeholder = (BlockPlaceholderNode) block.firstInstruction; // The EndNode for the already existing edge. - EndNode end = currentGraph.add(new EndNode()); + AbstractEndNode end = currentGraph.add(new EndNode()); // The MergeNode that replaces the placeholder. MergeNode mergeNode = currentGraph.add(new MergeNode()); FixedNode next = placeholder.next(); @@ -1509,7 +1499,7 @@ MergeNode mergeNode = (MergeNode) block.firstInstruction; // The EndNode for the newly merged edge. - EndNode newEnd = currentGraph.add(new EndNode()); + AbstractEndNode newEnd = currentGraph.add(new EndNode()); Target target = checkLoopExit(newEnd, block, state); FixedNode result = target.fixed; block.entryState.merge(mergeNode, target.state); @@ -1523,9 +1513,9 @@ * Returns a block begin node with the specified state. If the specified probability is 0, the * block deoptimizes immediately. */ - private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) { + private AbstractBeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) { FixedNode target = createTarget(probability, block, stateAfter); - BeginNode begin = BeginNode.begin(target); + AbstractBeginNode begin = AbstractBeginNode.begin(target); assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize " + "to a bci _before_ the actual if, so that the interpreter can update the profiling information."; @@ -1666,7 +1656,7 @@ if (typeInstruction != null) { Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); ValueNode exception = frameState.stackAt(0); - CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null)); + CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false)); frameState.apop(); frameState.push(Kind.Object, checkCast); FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState); @@ -1706,7 +1696,7 @@ if (block.isLoopHeader) { // Create the loop header block, which later will merge the backward branches of the // loop. - EndNode preLoopEnd = currentGraph.add(new EndNode()); + AbstractEndNode preLoopEnd = currentGraph.add(new EndNode()); LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode()); lastInstr.setNext(preLoopEnd); // Add the single non-loop predecessor of the loop header. @@ -1774,7 +1764,7 @@ frameState.clearNonLiveLocals(currentBlock.localsLiveOut); } if (lastInstr instanceof StateSplit) { - if (lastInstr.getClass() == BeginNode.class) { + if (lastInstr.getClass() == AbstractBeginNode.class) { // BeginNodes do not need a frame state } else { StateSplit stateSplit = (StateSplit) lastInstr; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Mon May 13 17:11:31 2013 +0200 @@ -60,9 +60,9 @@ Object[] args = argsWithReceiver(receiver, argsToBind); JavaType[] parameterTypes = signatureToTypes(runtime.lookupJavaMethod(m)); assert parameterTypes.length == args.length; - for (int i = 0; i < argsToBind.length; i++) { + for (int i = 0; i < args.length; i++) { LocalNode local = graph.getLocal(i); - Constant c = Constant.forBoxed(parameterTypes[i].getKind(), argsToBind[i]); + Constant c = Constant.forBoxed(parameterTypes[i].getKind(), args[i]); ConstantNode replacement = ConstantNode.forConstant(c, runtime, graph); local.replaceAtUsages(replacement); } @@ -99,8 +99,10 @@ Result expect = executeExpected(method, receiver, args); test(method, expect, receiver, args); - this.argsToBind = args; - test(method, expect, receiver, args); - this.argsToBind = null; + if (args.length > 0) { + this.argsToBind = args; + test(method, expect, receiver, args); + this.argsToBind = null; + } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_currentTimeMillis02.java Mon May 13 17:11:31 2013 +0200 @@ -36,8 +36,8 @@ delta = System.currentTimeMillis() - start; // do nothing. } - // better get at least 40 millisecond resolution. - return delta >= 1 && delta < 40; + // better get at least 100 millisecond resolution. + return delta >= 1 && delta < 100; } @Test diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Reflection_getCallerClass01.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.jtt.reflect; - -import com.oracle.graal.jtt.*; -import org.junit.*; - -import sun.reflect.*; - -/* - */ -public final class Reflection_getCallerClass01 extends JTTTest { - - public static final class Caller1 { - - private Caller1() { - } - - static String caller1(int depth) { - return Reflection.getCallerClass(depth).getName(); - } - } - - public static final class Caller2 { - - private Caller2() { - } - - static String caller2(int depth) { - return Caller1.caller1(depth); - } - } - - public static String test(int depth) { - return Caller2.caller2(depth); - } - - @Test - public void run0() throws Throwable { - runTest("test", 0); - } - - @Test - public void run1() throws Throwable { - runTest("test", 1); - } - - @Test - public void run2() throws Throwable { - runTest("test", 2); - } - -} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Mon May 13 17:11:31 2013 +0200 @@ -41,11 +41,11 @@ protected final Scale scale; protected final int displacement; - public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) { + public AMD64AddressValue(PlatformKind kind, AllocatableValue base, int displacement) { this(kind, base, Value.ILLEGAL, Scale.Times1, displacement); } - public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) { + public AMD64AddressValue(PlatformKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) { super(kind); this.base = base; this.index = index; @@ -54,7 +54,7 @@ } private static Register toRegister(AllocatableValue value) { - if (value == Value.ILLEGAL) { + if (value.equals(Value.ILLEGAL)) { return Register.None; } else { RegisterValue reg = (RegisterValue) value; @@ -91,13 +91,13 @@ public boolean equals(Object obj) { if (obj instanceof AMD64AddressValue) { AMD64AddressValue addr = (AMD64AddressValue) obj; - return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index); + return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index); } return false; } @Override public int hashCode() { - return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ (getKind().ordinal() << 12); + return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ getPlatformKind().hashCode(); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Mon May 13 17:11:31 2013 +0200 @@ -27,7 +27,9 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -36,8 +38,8 @@ public enum AMD64Arithmetic { IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, - FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR, - DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR, + FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, + DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, INEG, LNEG, I2L, L2I, I2B, I2C, I2S, F2D, D2F, @@ -255,8 +257,8 @@ public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) { this.opcode = opcode; - this.divResult = AMD64.rax.asValue(x.getKind()); - this.remResult = AMD64.rdx.asValue(x.getKind()); + this.divResult = AMD64.rax.asValue(x.getPlatformKind()); + this.remResult = AMD64.rdx.asValue(x.getPlatformKind()); this.x = x; this.y = y; this.state = state; @@ -278,6 +280,64 @@ } } + public static class FPDivRemOp extends AMD64LIRInstruction { + @Opcode private final AMD64Arithmetic opcode; + @Def protected AllocatableValue result; + @Use protected AllocatableValue x; + @Use protected AllocatableValue y; + @Temp protected AllocatableValue raxTemp; + + public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + this.opcode = opcode; + this.result = result; + this.raxTemp = AMD64.rax.asValue(Kind.Int); + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + AMD64Address tmp = new AMD64Address(AMD64.rsp); + masm.subq(AMD64.rsp, 8); + if (opcode == FREM) { + masm.movflt(tmp, asRegister(y)); + masm.fld_s(tmp); + masm.movflt(tmp, asRegister(x)); + masm.fld_s(tmp); + } else { + assert opcode == DREM; + masm.movsd(tmp, asRegister(y)); + masm.fld_d(tmp); + masm.movsd(tmp, asRegister(x)); + masm.fld_d(tmp); + } + + Label label = new Label(); + masm.bind(label); + masm.fprem(); + masm.fwait(); + masm.fnstsw_ax(); + masm.testl(AMD64.rax, 0x400); + masm.jcc(ConditionFlag.NotZero, label); + masm.fxch(1); + masm.fpop(); + + if (opcode == FREM) { + masm.fstp_s(tmp); + masm.movflt(asRegister(result), tmp); + } else { + masm.fstp_d(tmp); + masm.movsd(asRegister(result), tmp); + } + masm.addq(AMD64.rsp, 8); + } + + @Override + protected void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } @SuppressWarnings("unused") protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Mon May 13 17:11:31 2013 +0200 @@ -51,7 +51,7 @@ } @Override - public boolean hasCall() { + public boolean destroysCallerSavedRegisters() { return true; } } @@ -112,8 +112,8 @@ } @Override - public boolean hasCall() { - return !callTarget.preservesRegisters(); + public boolean destroysCallerSavedRegisters() { + return callTarget.destroysRegisters(); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegistersPreservationOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegistersPreservationOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.lir.*; + +/** + * Base class for operations that preserve a set of registers. + */ +public abstract class AMD64RegistersPreservationOp extends AMD64LIRInstruction { + + /** + * Prunes the set of registers preserved by this operation to exclude those in {@code ignored} + * and updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description} + * of where each preserved register is saved. + */ + public abstract void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Restores registers from stack slots. + */ +@Opcode("RESTORE_REGISTER") +public class AMD64RestoreRegistersOp extends AMD64LIRInstruction { + + /** + * The slots from which the registers are restored. + */ + @Use(STACK) protected final StackSlot[] slots; + + /** + * The operation that saved the registers restored by this operation. + */ + private final AMD64SaveRegistersOp save; + + public AMD64RestoreRegistersOp(StackSlot[] source, AMD64SaveRegistersOp save) { + this.slots = source; + this.save = save; + } + + protected Register[] getSavedRegisters() { + return save.savedRegisters; + } + + protected void restoreRegister(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register register, StackSlot input) { + RegisterValue result = register.asValue(input.getKind()); + AMD64Move.move(tasm, masm, result, input); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + Register[] savedRegisters = getSavedRegisters(); + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + restoreRegister(tasm, masm, savedRegisters[i], slots[i]); + } + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Saves registers to stack slots. + */ +@Opcode("SAVE_REGISTER") +public class AMD64SaveRegistersOp extends AMD64RegistersPreservationOp { + + /** + * The registers (potentially) saved by this operation. + */ + protected final Register[] savedRegisters; + + /** + * The slots to which the registers are saved. + */ + @Def(STACK) protected final StackSlot[] slots; + + public AMD64SaveRegistersOp(Register[] savedRegisters, StackSlot[] slots) { + this.savedRegisters = savedRegisters; + this.slots = slots; + } + + protected void saveRegister(TargetMethodAssembler tasm, AMD64MacroAssembler masm, StackSlot result, Register register) { + RegisterValue input = register.asValue(result.getKind()); + AMD64Move.move(tasm, masm, result, input); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + saveRegister(tasm, masm, slots[i], savedRegisters[i]); + } + } + } + + public StackSlot[] getSlots() { + return slots; + } + + /** + * Prunes the set of registers saved by this operation to exclude those in {@code ignored} and + * updates {@code debugInfo} with a {@linkplain DebugInfo#getCalleeSaveInfo() description} of + * where each preserved register is saved. + */ + @Override + public void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap) { + int preserved = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + if (ignored.contains(savedRegisters[i])) { + savedRegisters[i] = null; + } else { + preserved++; + } + } + } + if (preserved != 0) { + Register[] keys = new Register[preserved]; + int[] values = new int[keys.length]; + int mapIndex = 0; + for (int i = 0; i < savedRegisters.length; i++) { + if (savedRegisters[i] != null) { + keys[mapIndex] = savedRegisters[i]; + values[mapIndex] = frameMap.indexForStackSlot(slots[i]); + mapIndex++; + } + } + assert mapIndex == preserved; + debugInfo.setCalleeSaveInfo(new RegisterSaveLayout(keys, values)); + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Writes well known garbage values to registers. + */ +@Opcode("ZAP_REGISTER") +public final class AMD64ZapRegistersOp extends AMD64RegistersPreservationOp { + + /** + * The registers that are zapped. + */ + protected final Register[] zappedRegisters; + + /** + * The garbage values that are written to the registers. + */ + @Use({CONST}) protected Constant[] zapValues; + + public AMD64ZapRegistersOp(Register[] zappedRegisters, Constant[] zapValues) { + this.zappedRegisters = zappedRegisters; + this.zapValues = zapValues; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + for (int i = 0; i < zappedRegisters.length; i++) { + if (zappedRegisters[i] != null) { + RegisterValue registerValue = zappedRegisters[i].asValue(zapValues[i].getPlatformKind()); + AMD64Move.move(tasm, masm, registerValue, zapValues[i]); + } + } + } + + /** + * Prunes the set of registers zapped by this operation to exclude those in {@code ignored}. + */ + @Override + public void update(Set ignored, DebugInfo debugInfo, FrameMap frameMap) { + for (int i = 0; i < zappedRegisters.length; i++) { + if (zappedRegisters[i] != null) { + if (ignored.contains(zappedRegisters[i])) { + zappedRegisters[i] = null; + } + } + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java Mon May 13 17:11:31 2013 +0200 @@ -48,7 +48,7 @@ * @param kind the kind of the value being addressed * @param base the base register */ - public PTXAddressValue(Kind kind, AllocatableValue base) { + public PTXAddressValue(PlatformKind kind, AllocatableValue base) { this(kind, base, 0); } @@ -60,7 +60,7 @@ * @param base the base register * @param displacement the displacement */ - public PTXAddressValue(Kind kind, AllocatableValue base, long displacement) { + public PTXAddressValue(PlatformKind kind, AllocatableValue base, long displacement) { super(kind); this.base = base; this.displacement = displacement; @@ -95,13 +95,13 @@ public boolean equals(Object obj) { if (obj instanceof PTXAddressValue) { PTXAddressValue addr = (PTXAddressValue) obj; - return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base); + return getPlatformKind() == addr.getPlatformKind() && displacement == addr.displacement && base.equals(addr.base); } return false; } @Override public int hashCode() { - return base.hashCode() ^ ((int) displacement << 4) ^ (getKind().ordinal() << 12); + return base.hashCode() ^ ((int) displacement << 4) ^ getPlatformKind().hashCode(); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java Mon May 13 17:11:31 2013 +0200 @@ -45,7 +45,7 @@ private final CompositeValueClass valueClass; - public CompositeValue(Kind kind) { + public CompositeValue(PlatformKind kind) { super(kind); valueClass = CompositeValueClass.get(getClass()); } @@ -58,4 +58,18 @@ public String toString() { return valueClass.toString(this); } + + @Override + public int hashCode() { + return 53 * super.hashCode() + valueClass.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CompositeValue) { + CompositeValue other = (CompositeValue) obj; + return super.equals(other) && valueClass.equals(other.valueClass); + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Mon May 13 17:11:31 2013 +0200 @@ -91,7 +91,7 @@ if (op1 instanceof MoveOp && op2 instanceof MoveOp) { MoveOp move1 = (MoveOp) op1; MoveOp move2 = (MoveOp) op2; - if (move1.getInput() == move2.getInput() && move1.getResult() == move2.getResult()) { + if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) { // these moves are exactly equal and can be optimized return true; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Mon May 13 17:11:31 2013 +0200 @@ -198,7 +198,7 @@ // Without this, frameNeedsAllocating() would never return true. int total = 0; for (StackSlot s : freedSlots) { - total += target.sizeInBytes(s.getKind()); + total += target.arch.getSizeInBytes(s.getKind()); } int initialSpillSize = returnAddressSize() + calleeSaveAreaSize(); if (total == spillSize - initialSpillSize) { @@ -211,8 +211,7 @@ } /** - * Computes the offset of a stack slot relative to the frame register. This is also the bit - * index of stack slots in the reference map. + * Computes the offset of a stack slot relative to the frame register. * * @param slot a stack slot * @return the offset of the stack slot @@ -227,6 +226,18 @@ } /** + * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack + * slots in the reference map. + * + * @param slot a stack slot + * @return the index of the stack slot + */ + public int indexForStackSlot(StackSlot slot) { + assert offsetForStackSlot(slot) % target.wordSize == 0; + return offsetForStackSlot(slot) / target.wordSize; + } + + /** * Gets the offset to the stack area where callee-saved registers are stored. * * @return The offset to the callee save area (in bytes). @@ -256,7 +267,7 @@ hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0; } - private StackSlot getSlot(Kind kind, int additionalOffset) { + private StackSlot getSlot(PlatformKind kind, int additionalOffset) { return StackSlot.get(kind, -spillSize + additionalOffset, true); } @@ -267,12 +278,12 @@ * @param kind The kind of the spill slot to be reserved. * @return A spill slot denoting the reserved memory area. */ - public StackSlot allocateSpillSlot(Kind kind) { + public StackSlot allocateSpillSlot(PlatformKind kind) { assert frameSize == -1 : "frame size must not yet be fixed"; if (freedSlots != null) { for (Iterator iter = freedSlots.iterator(); iter.hasNext();) { StackSlot s = iter.next(); - if (s.getKind() == kind) { + if (s.getPlatformKind() == kind) { iter.remove(); if (freedSlots.isEmpty()) { freedSlots = null; @@ -281,20 +292,20 @@ } } } - int size = target.sizeInBytes(kind); + int size = target.arch.getSizeInBytes(kind); spillSize = NumUtil.roundUp(spillSize + size, size); return getSlot(kind, 0); } - private List freedSlots; + private Set freedSlots; /** - * Frees a spill slot that was obtained via {@link #allocateSpillSlot(Kind)} such that it can be - * reused for the next allocation request for the same kind of slot. + * Frees a spill slot that was obtained via {@link #allocateSpillSlot(PlatformKind)} such that + * it can be reused for the next allocation request for the same kind of slot. */ public void freeSpillSlot(StackSlot slot) { if (freedSlots == null) { - freedSlots = new ArrayList<>(); + freedSlots = new HashSet<>(); } freedSlots.add(slot); } @@ -330,11 +341,6 @@ } } - private int frameRefMapIndex(StackSlot slot) { - assert offsetForStackSlot(slot) % target.wordSize == 0; - return offsetForStackSlot(slot) / target.wordSize; - } - /** * Initializes a reference map that covers all registers of the target architecture. */ @@ -369,7 +375,7 @@ if (isRegister(location)) { registerRefMap.set(asRegister(location).number); } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); + int index = indexForStackSlot(asStackSlot(location)); frameRefMap.set(index); } else { assert isConstant(location); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Mon May 13 17:11:31 2013 +0200 @@ -84,16 +84,16 @@ /** * The value must have been defined before. It is alive before the instruction until the * beginning of the instruction, but not necessarily throughout the instruction. A register - * assigned to it can also be assigend to a Temp or Output operand. The value can be used - * again after the instruction, so the instruction must not modify the register. + * assigned to it can also be assigned to a {@link #TEMP} or {@link #DEF} operand. The value + * can be used again after the instruction, so the instruction must not modify the register. */ USE, /** * The value must have been defined before. It is alive before the instruction and - * throughout the instruction. A register assigned to it cannot be assigned to a Temp or - * Output operand. The value can be used again after the instruction, so the instruction - * must not modify the register. + * throughout the instruction. A register assigned to it cannot be assigned to a + * {@link #TEMP} or {@link #DEF} operand. The value can be used again after the instruction, + * so the instruction must not modify the register. */ ALIVE, @@ -244,7 +244,7 @@ } public final boolean hasOperands() { - return instructionClass.hasOperands() || hasState() || hasCall(); + return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters(); } public final boolean hasState() { @@ -252,10 +252,9 @@ } /** - * Returns true when this instruction is a call instruction that destroys all caller-saved - * registers. + * Determines if this instruction destroys all caller-saved registers.. */ - public boolean hasCall() { + public boolean destroysCallerSavedRegisters() { return false; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Mon May 13 17:11:31 2013 +0200 @@ -138,7 +138,7 @@ curInstruction = op; op.forEachInput(useProc); - if (op.hasCall()) { + if (op.destroysCallerSavedRegisters()) { for (Register register : frameMap.registerConfig.getCallerSaveRegisters()) { curRegistersLive[register.number] = null; } @@ -179,7 +179,7 @@ curRegistersDefined.set(regNum); } - if (beforeRegisterAllocation && curRegistersLive[regNum] != value) { + if (beforeRegisterAllocation && !curRegistersLive[regNum].equals(value)) { TTY.println("block %s instruction %s", curBlock, curInstruction); TTY.println("live registers: %s", Arrays.toString(curRegistersLive)); TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Mon May 13 17:11:31 2013 +0200 @@ -39,31 +39,33 @@ public final int index; /** - * The type of register that this variable needs to get assigned. - */ - public final Register.RegisterFlag flag; - - /** * Creates a new variable. * * @param kind * @param index */ - public Variable(Kind kind, int index, Register.RegisterFlag flag) { + public Variable(PlatformKind kind, int index) { super(kind); - assert kind == kind.getStackKind() : "Variables can be only created for stack kinds"; assert index >= 0; this.index = index; - this.flag = flag; - } - - @Override - public int hashCode() { - return (index << 4) | getKind().ordinal(); } @Override public String toString() { return "v" + index + getKindSuffix(); } + + @Override + public int hashCode() { + return 71 * super.hashCode() + index; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Variable) { + Variable other = (Variable) obj; + return super.equals(other) && index == other.index; + } + return false; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Mon May 13 17:11:31 2013 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; public class TargetMethodAssembler { @@ -88,7 +89,7 @@ compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s)); } - public CompilationResult finishTargetMethod(Object name, boolean isStub) { + public CompilationResult finishTargetMethod(StructuredGraph graph) { // Install code, data and frame size compilationResult.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); @@ -113,11 +114,11 @@ Debug.metric("TargetMethods").increment(); Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); - Debug.metric("SafepointsEmitted").add(compilationResult.getInfopoints().size()); + Debug.metric("InfopointsEmitted").add(compilationResult.getInfopoints().size()); Debug.metric("DataPatches").add(ldp.size()); Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); } - Debug.log("Finished target method %s, isStub %b", name, isStub); + Debug.log("Finished compiling %s", graph); return compilationResult; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java Mon May 13 17:11:31 2013 +0200 @@ -22,9 +22,11 @@ */ package com.oracle.graal.loop; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.ConvertNode.Op; import com.oracle.graal.nodes.type.*; public class BasicInductionVariable extends InductionVariable { @@ -113,8 +115,19 @@ } @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init); + public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { + Kind fromKind = phi.kind(); + Graph graph = phi.graph(); + ValueNode stride = strideNode(); + ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount); + ValueNode initNode = this.initNode(); + if (fromKind != kind) { + Op convertOp = Op.getOp(fromKind, kind); + stride = graph.unique(new ConvertNode(convertOp, stride)); + maxTripCount = graph.unique(new ConvertNode(convertOp, maxTripCount)); + initNode = graph.unique(new ConvertNode(convertOp, initNode)); + } + return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(stride, IntegerArithmeticNode.sub(maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode); } @Override @@ -124,6 +137,6 @@ @Override public long constantExtremum() { - return constantStride() * loop.counted().constantMaxTripCount() + constantInit(); + return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit(); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java Mon May 13 17:11:31 2013 +0200 @@ -22,9 +22,15 @@ */ package com.oracle.graal.loop; +import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.loop.InductionVariable.Direction; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; public class CountedLoopInfo { @@ -32,19 +38,38 @@ private InductionVariable iv; private ValueNode end; private boolean oneOff; + private AbstractBeginNode body; - CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) { + CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff, AbstractBeginNode body) { this.loop = loop; this.iv = iv; this.end = end; this.oneOff = oneOff; + this.body = body; } public ValueNode maxTripCountNode() { - // TODO (gd) stuarte and respect oneOff - throw GraalInternalError.unimplemented("division is a fixed node that needs to be inserted into the control flow"); - // return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), - // iv.strideNode()); + return maxTripCountNode(false); + } + + public ValueNode maxTripCountNode(boolean assumePositive) { + StructuredGraph graph = iv.valueNode().graph(); + Kind kind = iv.valueNode().kind(); + IntegerArithmeticNode range = IntegerArithmeticNode.sub(end, iv.initNode()); + if (oneOff) { + if (iv.direction() == Direction.Up) { + range = IntegerArithmeticNode.add(range, ConstantNode.forIntegerKind(kind, 1, graph)); + } else { + range = IntegerArithmeticNode.sub(range, ConstantNode.forIntegerKind(kind, 1, graph)); + } + } + IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode())); + graph.addBeforeFixed(loop.entryPoint(), div); + ConstantNode zero = ConstantNode.forIntegerKind(kind, 0, graph); + if (assumePositive) { + return div; + } + return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero)); } public boolean isConstantMaxTripCount() { @@ -80,4 +105,60 @@ public String toString() { return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : ""); } + + public ValueNode getLimit() { + return end; + } + + public ValueNode getStart() { + return iv.initNode(); + } + + public boolean isLimitIncluded() { + return oneOff; + } + + public AbstractBeginNode getBody() { + return body; + } + + public Direction getDirection() { + return iv.direction(); + } + + public GuardingNode getOverFlowGuard() { + return loop.loopBegin().getOverflowGuard(); + } + + public GuardingNode createOverFlowGuard() { + GuardingNode overflowGuard = getOverFlowGuard(); + if (overflowGuard != null) { + return overflowGuard; + } + Kind kind = iv.valueNode().kind(); + Graph graph = iv.valueNode().graph(); + CompareNode cond; // we use a negated guard with a < condition to achieve a >= + ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph); + if (iv.direction() == Direction.Up) { + IntegerArithmeticNode v1 = sub(ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(iv.strideNode(), one)); + if (oneOff) { + v1 = sub(v1, one); + } + cond = graph.unique(new IntegerLessThanNode(v1, end)); + } else { + assert iv.direction() == Direction.Down; + IntegerArithmeticNode v1 = add(ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(one, iv.strideNode())); + if (oneOff) { + v1 = add(v1, one); + } + cond = graph.unique(new IntegerLessThanNode(end, v1)); + } + overflowGuard = graph.unique(new GuardNode(cond, BeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true)); + loop.loopBegin().setOverflowGuard(overflowGuard); + return overflowGuard; + } + + public Kind getKind() { + return iv.valueNode().kind(); + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.loop; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -86,8 +87,8 @@ } @Override - public ValueNode extremumNode() { - return op(offset, base.extremumNode()); + public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { + return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, offset)); } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.loop; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; @@ -96,8 +97,8 @@ } @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.mul(base.extremumNode(), scale); + public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) { + return IntegerArithmeticNode.mul(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale)); } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.loop; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -48,6 +49,10 @@ this.loop = loop; } + public LoopEx getLoop() { + return loop; + } + public abstract Direction direction(); public abstract ValueNode valueNode(); @@ -64,7 +69,11 @@ public abstract long constantStride(); - public abstract ValueNode extremumNode(); + public ValueNode extremumNode() { + return extremumNode(false, valueNode().kind()); + } + + public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind); public abstract boolean isConstantExtremum(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java Mon May 13 17:11:31 2013 +0200 @@ -46,7 +46,7 @@ private Collection findBasic() { List bivs = new LinkedList<>(); LoopBeginNode loopBegin = loop.loopBegin(); - EndNode forwardEnd = loopBegin.forwardEnd(); + AbstractEndNode forwardEnd = loopBegin.forwardEnd(); for (PhiNode phi : loopBegin.phis()) { ValueNode backValue = phi.singleBackValue(); if (backValue == null) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Mon May 13 17:11:31 2013 +0200 @@ -39,6 +39,7 @@ private LoopFragmentWhole whole; private CountedLoopInfo counted; // TODO (gd) detect private LoopsData data; + private InductionVariables ivs; LoopEx(Loop lirLoop, LoopsData data) { this.lirLoop = lirLoop; @@ -125,7 +126,7 @@ public void reassociateInvariants() { InvariantPredicate invariant = new InvariantPredicate(); - StructuredGraph graph = (StructuredGraph) loopBegin().graph(); + StructuredGraph graph = loopBegin().graph(); for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) { if (!BinaryNode.canTryReassociate(binary)) { continue; @@ -148,9 +149,9 @@ return data; } - public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) { - Collection blocks = new LinkedList<>(); - Collection exits = new LinkedList<>(); + public NodeBitMap nodesInLoopFrom(AbstractBeginNode point, AbstractBeginNode until) { + Collection blocks = new LinkedList<>(); + Collection exits = new LinkedList<>(); Queue work = new LinkedList<>(); ControlFlowGraph cfg = loopsData().controlFlowGraph(); work.add(cfg.blockFor(point)); @@ -169,4 +170,11 @@ } return LoopFragment.computeNodes(point.graph(), blocks, exits); } + + public InductionVariables getInductionVariables() { + if (ivs == null) { + ivs = new InductionVariables(this); + } + return ivs; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Mon May 13 17:11:31 2013 +0200 @@ -95,7 +95,7 @@ } else { l = loop(); } - return (StructuredGraph) l.loopBegin().graph(); + return l.loopBegin().graph(); } protected abstract DuplicationReplacement getDuplicationReplacement(); @@ -145,13 +145,13 @@ } } - protected static NodeBitMap computeNodes(Graph graph, Collection blocks) { - return computeNodes(graph, blocks, Collections. emptyList()); + protected static NodeBitMap computeNodes(Graph graph, Collection blocks) { + return computeNodes(graph, blocks, Collections. emptyList()); } - protected static NodeBitMap computeNodes(Graph graph, Collection blocks, Collection earlyExits) { + protected static NodeBitMap computeNodes(Graph graph, Collection blocks, Collection earlyExits) { final NodeBitMap nodes = graph.createNodeBitMap(true); - for (BeginNode b : blocks) { + for (AbstractBeginNode b : blocks) { for (Node n : b.getBlockNodes()) { if (n instanceof Invoke) { nodes.mark(((Invoke) n).callTarget()); @@ -165,7 +165,7 @@ nodes.mark(n); } } - for (BeginNode earlyExit : earlyExits) { + for (AbstractBeginNode earlyExit : earlyExits) { FrameState stateAfter = earlyExit.stateAfter(); if (stateAfter != null) { nodes.mark(stateAfter); @@ -183,10 +183,11 @@ } } - for (BeginNode b : blocks) { + final NodeBitMap notloopNodes = graph.createNodeBitMap(true); + for (AbstractBeginNode b : blocks) { for (Node n : b.getBlockNodes()) { for (Node usage : n.usages()) { - markFloating(usage, nodes); + markFloating(usage, nodes, notloopNodes); } } } @@ -194,10 +195,13 @@ return nodes; } - private static boolean markFloating(Node n, NodeBitMap loopNodes) { + private static boolean markFloating(Node n, NodeBitMap loopNodes, NodeBitMap notloopNodes) { if (loopNodes.isMarked(n)) { return true; } + if (notloopNodes.isMarked(n)) { + return false; + } if (n instanceof FixedNode) { return false; } @@ -208,11 +212,12 @@ if (mark) { loopNodes.mark(n); } else { + notloopNodes.mark(n); return false; } } for (Node usage : n.usages()) { - if (markFloating(usage, loopNodes)) { + if (markFloating(usage, loopNodes, notloopNodes)) { mark = true; } } @@ -220,11 +225,12 @@ loopNodes.mark(n); return true; } + notloopNodes.mark(n); return false; } - public static Collection toHirBlocks(Collection blocks) { - List hir = new ArrayList<>(blocks.size()); + public static Collection toHirBlocks(Collection blocks) { + List hir = new ArrayList<>(blocks.size()); for (Block b : blocks) { hir.add(b.getBeginNode()); } @@ -238,18 +244,18 @@ protected void mergeEarlyExits() { assert isDuplicate(); StructuredGraph graph = graph(); - for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) { + for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) { FixedNode next = earlyExit.next(); if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) { continue; } - BeginNode newEarlyExit = getDuplicatedNode(earlyExit); + AbstractBeginNode newEarlyExit = getDuplicatedNode(earlyExit); if (newEarlyExit == null) { continue; } MergeNode merge = graph.add(new MergeNode()); - EndNode originalEnd = graph.add(new EndNode()); - EndNode newEnd = graph.add(new EndNode()); + AbstractEndNode originalEnd = graph.add(new EndNode()); + AbstractEndNode newEnd = graph.add(new EndNode()); merge.addForwardEnd(originalEnd); merge.addForwardEnd(newEnd); earlyExit.setNext(originalEnd); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Mon May 13 17:11:31 2013 +0200 @@ -89,13 +89,13 @@ patchNodes(dataFixBefore); - BeginNode end = mergeEnds(); + AbstractBeginNode end = mergeEnds(); original().patchPeeling(this); mergeEarlyExits(); - BeginNode entry = getDuplicatedNode(loop.loopBegin()); + AbstractBeginNode entry = getDuplicatedNode(loop.loopBegin()); FrameState state = entry.stateAfter(); if (state != null) { entry.setStateAfter(null); @@ -148,7 +148,7 @@ private void patchPeeling(LoopFragmentInside peel) { LoopBeginNode loopBegin = loop().loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); + StructuredGraph graph = loopBegin.graph(); List newPhis = new LinkedList<>(); for (PhiNode phi : loopBegin.phis().snapshot()) { ValueNode first; @@ -213,24 +213,24 @@ } } - private BeginNode mergeEnds() { + private AbstractBeginNode mergeEnds() { assert isDuplicate(); - List endsToMerge = new LinkedList<>(); - Map reverseEnds = new HashMap<>(); // map peel's exit to the - // corresponding loop exits + List endsToMerge = new LinkedList<>(); + Map reverseEnds = new HashMap<>(); // map peel's exit to the + // corresponding loop exits LoopBeginNode loopBegin = original().loop().loopBegin(); for (LoopEndNode le : loopBegin.loopEnds()) { - EndNode duplicate = getDuplicatedNode(le); + AbstractEndNode duplicate = getDuplicatedNode(le); if (duplicate != null) { endsToMerge.add(duplicate); reverseEnds.put(duplicate, le); } } mergedInitializers = new IdentityHashMap<>(); - BeginNode newExit; + AbstractBeginNode newExit; StructuredGraph graph = graph(); if (endsToMerge.size() == 1) { - EndNode end = endsToMerge.get(0); + AbstractEndNode end = endsToMerge.get(0); assert end.usages().count() == 0; newExit = graph.add(new BeginNode()); end.replaceAtPredecessor(newExit); @@ -245,13 +245,13 @@ duplicateState = state.duplicateWithVirtualState(); newExitMerge.setStateAfter(duplicateState); } - for (EndNode end : endsToMerge) { + for (AbstractEndNode end : endsToMerge) { newExitMerge.addForwardEnd(end); } for (final PhiNode phi : loopBegin.phis().snapshot()) { final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity())); - for (EndNode end : newExitMerge.forwardEnds()) { + for (AbstractEndNode end : newExitMerge.forwardEnds()) { LoopEndNode loopEnd = reverseEnds.get(end); ValueNode prim = prim(phi.valueAt(loopEnd)); assert prim != null; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Mon May 13 17:11:31 2013 +0200 @@ -60,12 +60,12 @@ public static boolean shouldUnswitch(LoopEx loop, ControlSplitNode controlSplit) { Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator(); - BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null; + AbstractBeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null; int loopTotal = loop.size(); int inBranchTotal = 0; double maxProbability = 0; for (Node successor : controlSplit.successors()) { - BeginNode branch = (BeginNode) successor; + AbstractBeginNode branch = (AbstractBeginNode) successor; inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality(); // this may count // twice because // of fall-through diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Mon May 13 17:11:31 2013 +0200 @@ -56,7 +56,7 @@ // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count int iterations = 0; LoopBeginNode loopBegin = loop.loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); + StructuredGraph graph = loopBegin.graph(); while (!loopBegin.isDeleted()) { int mark = graph.getMark(); peel(loop); @@ -78,19 +78,19 @@ // original loop is used as first successor Position firstPosition = successors.nextPosition(); NodeClass controlSplitClass = controlSplitNode.getNodeClass(); - controlSplitClass.set(newControlSplit, firstPosition, BeginNode.begin(originalLoop.entryPoint())); + controlSplitClass.set(newControlSplit, firstPosition, AbstractBeginNode.begin(originalLoop.entryPoint())); - StructuredGraph graph = (StructuredGraph) controlSplitNode.graph(); + StructuredGraph graph = controlSplitNode.graph(); while (successors.hasNext()) { Position position = successors.nextPosition(); // create a new loop duplicate, connect it and simplify it LoopFragmentWhole duplicateLoop = originalLoop.duplicate(); - controlSplitClass.set(newControlSplit, position, BeginNode.begin(duplicateLoop.entryPoint())); + controlSplitClass.set(newControlSplit, position, AbstractBeginNode.begin(duplicateLoop.entryPoint())); ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode); - graph.removeSplitPropagate(duplicatedControlSplit, (BeginNode) controlSplitClass.get(duplicatedControlSplit, position)); + graph.removeSplitPropagate(duplicatedControlSplit, (AbstractBeginNode) controlSplitClass.get(duplicatedControlSplit, position)); } // original loop is simplified last to avoid deleting controlSplitNode too early - graph.removeSplitPropagate(controlSplitNode, (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition)); + graph.removeSplitPropagate(controlSplitNode, (AbstractBeginNode) controlSplitClass.get(controlSplitNode, firstPosition)); // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Mon May 13 17:11:31 2013 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; public class LoopsData { @@ -92,6 +93,9 @@ InductionVariables ivs = new InductionVariables(loop); LoopBeginNode loopBegin = loop.loopBegin(); FixedNode next = loopBegin.next(); + while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode) { + next = ((FixedWithNextNode) next).next(); + } if (next instanceof IfNode) { IfNode ifNode = (IfNode) next; boolean negated = false; @@ -150,7 +154,7 @@ default: throw GraalInternalError.shouldNotReachHere(); } - loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff)); + loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff, negated ? ifNode.falseSuccessor() : ifNode.trueSuccessor())); } } } @@ -158,4 +162,18 @@ public ControlFlowGraph controlFlowGraph() { return cfg; } + + public InductionVariable getInductionVariable(ValueNode value) { + InductionVariable match = null; + for (LoopEx loop : loops()) { + InductionVariable iv = loop.getInductionVariables().get(value); + if (iv != null) { + if (match != null) { + return null; + } + match = iv; + } + } + return match; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011, 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.loop.phases; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; + +public class LoopSafepointEliminationPhase extends BasePhase { + + @Override + protected void run(StructuredGraph graph, MidTierContext context) { + LoopsData loops = new LoopsData(graph); + if (context.getOptimisticOptimizations().useLoopLimitChecks()) { + loops.detectedCountedLoops(); + for (LoopEx loop : loops.countedLoops()) { + if (loop.lirLoop().children.isEmpty() && loop.counted().getKind() == Kind.Int) { + loop.counted().createOverFlowGuard(); + for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) { + loopEnd.disableSafepoint(); + } + } + } + } + for (LoopEx loop : loops.countedLoops()) { + for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) { + Block b = loops.controlFlowGraph().blockFor(loopEnd); + blocks: while (b != loop.lirLoop().header) { + assert b != null; + for (FixedNode node : b.getNodes()) { + if (node instanceof Invoke || node instanceof RuntimeCallNode) { + loopEnd.disableSafepoint(); + break blocks; + } + } + b = b.getDominator(); + } + } + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Mon May 13 17:11:31 2013 +0200 @@ -77,7 +77,7 @@ sb.append(loop).append(" at ").append(controlSplit).append(" ["); NodeClassIterator it = controlSplit.successors().iterator(); while (it.hasNext()) { - sb.append(controlSplit.probability((BeginNode) it.next())); + sb.append(controlSplit.probability((AbstractBeginNode) it.next())); if (it.hasNext()) { sb.append(", "); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,193 @@ +/* + * 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; + +import static com.oracle.graal.graph.iterators.NodePredicates.*; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public abstract class AbstractBeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType, GuardingNode { + + @Input(notDataflow = true) private FrameState stateAfter; + + 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 false; + } + + protected AbstractBeginNode() { + super(StampFactory.dependency()); + } + + protected AbstractBeginNode(Stamp stamp) { + super(stamp); + } + + public static AbstractBeginNode begin(FixedNode with) { + if (with instanceof AbstractBeginNode) { + return (AbstractBeginNode) with; + } + AbstractBeginNode begin = with.graph().add(new BeginNode()); + begin.setNext(with); + return begin; + } + + @Override + public void simplify(SimplifierTool tool) { + FixedNode prev = (FixedNode) this.predecessor(); + if (prev == null) { + // This is the start node. + } else if (prev instanceof ControlSplitNode) { + // This begin node is necessary. + } else { + // This begin node can be removed and all guards moved up to the preceding begin node. + prepareDelete(); + tool.addToWorkList(next()); + graph().removeFixed(this); + } + } + + public static AbstractBeginNode prevBegin(FixedNode from) { + Node prevBegin = from; + while (prevBegin != null) { + if (prevBegin instanceof AbstractBeginNode) { + return (AbstractBeginNode) prevBegin; + } + prevBegin = prevBegin.predecessor(); + } + return null; + } + + private void evacuateGuards(FixedNode evacuateFrom) { + if (!usages().isEmpty()) { + AbstractBeginNode prevBegin = prevBegin(evacuateFrom); + assert prevBegin != null; + for (Node anchored : anchored().snapshot()) { + anchored.replaceFirstInput(this, prevBegin); + } + } + } + + public void prepareDelete() { + prepareDelete((FixedNode) predecessor()); + } + + public void prepareDelete(FixedNode evacuateFrom) { + removeProxies(); + evacuateGuards(evacuateFrom); + } + + public void removeProxies() { + for (ProxyNode vpn : proxies().snapshot()) { + // can not use graph.replaceFloating because vpn.value may be null during killCFG + vpn.replaceAtUsages(vpn.value()); + vpn.safeDelete(); + } + } + + @Override + public boolean verify() { + assertTrue(predecessor() != null || this == graph().start() || this instanceof MergeNode, "begin nodes must be connected"); + return super.verify(); + } + + @Override + public void generate(LIRGeneratorTool gen) { + // nop + } + + public NodeIterable guards() { + return usages().filter(GuardNode.class); + } + + public NodeIterable anchored() { + return usages().filter(isNotA(ProxyNode.class)); + } + + public NodeIterable proxies() { + return usages().filter(ProxyNode.class); + } + + public NodeIterable getBlockNodes() { + return new AbstractNodeIterable() { + + @Override + public Iterator iterator() { + return new BlockNodeIterator(AbstractBeginNode.this); + } + }; + } + + private class BlockNodeIterator implements Iterator { + + private FixedNode current; + + public BlockNodeIterator(FixedNode next) { + this.current = next; + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public FixedNode next() { + FixedNode ret = current; + if (ret == null) { + throw new NoSuchElementException(); + } + if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) { + current = null; + } else { + current = ((FixedWithNextNode) current).next(); + } + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public AbstractBeginNode asNode() { + return this; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,56 @@ +/* + * 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; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public abstract class AbstractEndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable { + + protected AbstractEndNode() { + super(StampFactory.forVoid()); + } + + @Override + public void generate(LIRGeneratorTool gen) { + gen.visitEndNode(this); + } + + public MergeNode merge() { + return (MergeNode) usages().first(); + } + + @Override + public boolean verify() { + assertTrue(usages().count() <= 1, "at most one usage"); + return super.verify(); + } + + @Override + public Iterable cfgSuccessors() { + return Arrays.asList(merge()); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; + +public abstract class AbstractLocalNode extends FloatingNode { + + private final int index; + + public AbstractLocalNode(int index, Stamp stamp) { + super(stamp); + this.index = index; + } + + /** + * Gets the index of this local in the array of parameters. This is NOT the JVM local index. + * + * @return the index + */ + public int index() { + return index; + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "(" + index + ")"; + } else { + return super.toString(verbosity); + } + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Mon May 13 17:11:31 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,32 +22,9 @@ */ package com.oracle.graal.nodes; -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public class BeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType { - - @Input(notDataflow = true) private FrameState stateAfter; - - 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 false; - } +public final class BeginNode extends AbstractBeginNode { public BeginNode() { super(StampFactory.dependency()); @@ -57,134 +34,6 @@ super(stamp); } - public static BeginNode begin(FixedNode with) { - if (with instanceof BeginNode) { - return (BeginNode) with; - } - BeginNode begin = with.graph().add(new BeginNode()); - begin.setNext(with); - return begin; - } - - @Override - public void simplify(SimplifierTool tool) { - FixedNode prev = (FixedNode) this.predecessor(); - if (prev == null) { - // This is the start node. - } else if (prev instanceof ControlSplitNode) { - // This begin node is necessary. - } else { - // This begin node can be removed and all guards moved up to the preceding begin node. - prepareDelete(); - tool.addToWorkList(next()); - ((StructuredGraph) graph()).removeFixed(this); - } - } - - public static BeginNode prevBegin(FixedNode from) { - Node prevBegin = from; - while (prevBegin != null) { - if (prevBegin instanceof BeginNode) { - return (BeginNode) prevBegin; - } - prevBegin = prevBegin.predecessor(); - } - return null; - } - - private void evacuateGuards(FixedNode evacuateFrom) { - if (!usages().isEmpty()) { - BeginNode prevBegin = prevBegin(evacuateFrom); - assert prevBegin != null; - for (Node anchored : anchored().snapshot()) { - anchored.replaceFirstInput(this, prevBegin); - } - } - } - - public void prepareDelete() { - prepareDelete((FixedNode) predecessor()); - } - - public void prepareDelete(FixedNode evacuateFrom) { - removeProxies(); - evacuateGuards(evacuateFrom); - } - - public void removeProxies() { - for (ProxyNode vpn : proxies().snapshot()) { - // can not use graph.replaceFloating because vpn.value may be null during killCFG - vpn.replaceAtUsages(vpn.value()); - vpn.safeDelete(); - } - } - - @Override - public boolean verify() { - assertTrue(predecessor() != null || this == ((StructuredGraph) graph()).start() || this instanceof MergeNode, "begin nodes must be connected"); - return super.verify(); - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nop - } - - public NodeIterable guards() { - return usages().filter(GuardNode.class); - } - - public NodeIterable anchored() { - return usages().filter(isNotA(ProxyNode.class)); - } - - public NodeIterable proxies() { - return usages().filter(ProxyNode.class); - } - - public NodeIterable getBlockNodes() { - return new AbstractNodeIterable() { - - @Override - public Iterator iterator() { - return new BlockNodeIterator(BeginNode.this); - } - }; - } - - private class BlockNodeIterator implements Iterator { - - private FixedNode current; - - public BlockNodeIterator(FixedNode next) { - this.current = next; - } - - @Override - public boolean hasNext() { - return current != null; - } - - @Override - public FixedNode next() { - FixedNode ret = current; - if (ret == null) { - throw new NoSuchElementException(); - } - if (!(current instanceof FixedWithNextNode) || (current instanceof BeginNode && current != BeginNode.this)) { - current = null; - } else { - current = ((FixedWithNextNode) current).next(); - } - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - @NodeIntrinsic public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,11 +25,11 @@ import com.oracle.graal.nodes.type.*; /** - * Base class for {@link BeginNode}s that are associated with a frame state. TODO (dnsimon) this not - * needed until {@link BeginNode} no longer implements {@link StateSplit} which is not possible + * Base class for {@link AbstractBeginNode}s that are associated with a frame state. TODO (dnsimon) this not + * needed until {@link AbstractBeginNode} no longer implements {@link StateSplit} which is not possible * until loop peeling works without requiring begin nodes to have frames states */ -public abstract class BeginStateSplitNode extends BeginNode implements StateSplit { +public abstract class BeginStateSplitNode extends AbstractBeginNode implements StateSplit { public BeginStateSplitNode() { } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,9 +22,10 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.type.*; -public abstract class ControlSinkNode extends FixedNode { +public abstract class ControlSinkNode extends FixedNode implements Node.IterableNodeType { public ControlSinkNode(Stamp stamp) { super(stamp); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java Mon May 13 17:11:31 2013 +0200 @@ -34,5 +34,5 @@ super(stamp); } - public abstract double probability(BeginNode successor); + public abstract double probability(AbstractBeginNode successor); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes; -import java.util.*; - import com.oracle.graal.nodes.type.*; public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode { @@ -34,14 +32,6 @@ super(stamp); } - public DeoptimizingFixedWithNextNode(Stamp stamp, List dependencies) { - super(stamp, dependencies); - } - - public DeoptimizingFixedWithNextNode(Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - } - @Override public FrameState getDeoptimizationState() { return deoptState; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,35 +22,5 @@ */ package com.oracle.graal.nodes; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class EndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable { - - public EndNode() { - super(StampFactory.forVoid()); - } - - @Override - public void generate(LIRGeneratorTool gen) { - gen.visitEndNode(this); - } - - public MergeNode merge() { - return (MergeNode) usages().first(); - } - - @Override - public boolean verify() { - assertTrue(usages().count() <= 1, "at most one usage"); - return super.verify(); - } - - @Override - public Iterable cfgSuccessors() { - return Arrays.asList(merge()); - } +public final class EndNode extends AbstractEndNode { } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,7 @@ * This node will be inserted at point specified by {@link StructuredGraph#getEntryBCI()}, usually * by the graph builder. */ -public class EntryMarkerNode extends BeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable { +public class EntryMarkerNode extends AbstractBeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable { @Override public void simplify(SimplifierTool tool) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}") public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, Node.IterableNodeType, Negatable { @@ -83,7 +84,7 @@ if (condition instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition; if (c.getValue() != negated) { - ((StructuredGraph) graph()).removeFixed(this); + graph().removeFixed(this); } else { FixedNode next = this.next(); if (next != null) { @@ -97,11 +98,26 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - tool.getRuntime().lower(this, tool); + if (loweringType == LoweringType.BEFORE_GUARDS) { + tool.getRuntime().lower(this, tool); + } else { + FixedNode next = next(); + setNext(null); + DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason)); + IfNode ifNode; + if (negated) { + ifNode = graph().add(new IfNode(condition, deopt, next, 0)); + } else { + ifNode = graph().add(new IfNode(condition, next, deopt, 1)); + } + ((FixedWithNextNode) predecessor()).setNext(ifNode); + GraphUtil.killWithUnusedFloatingInputs(this); + } } @Override - public Negatable negate() { + public Negatable negate(LogicNode cond) { + assert cond == condition(); negated = !negated; return this; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes; -import java.util.*; - import com.oracle.graal.nodes.type.*; public abstract class FixedNode extends ValueNode { @@ -32,14 +30,6 @@ super(stamp); } - public FixedNode(Stamp stamp, List dependencies) { - super(stamp, dependencies); - } - - public FixedNode(Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - } - @Override public boolean verify() { assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float"); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes; -import java.util.*; - import com.oracle.graal.nodes.type.*; /** @@ -44,12 +42,4 @@ public FixedWithNextNode(Stamp stamp) { super(stamp); } - - public FixedWithNextNode(Stamp stamp, List dependencies) { - super(stamp, dependencies); - } - - public FixedWithNextNode(Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; + +public abstract class FloatingGuardedNode extends FloatingNode implements GuardedNode { + + @Input private GuardingNode guard; + + public FloatingGuardedNode(Stamp stamp) { + super(stamp); + } + + public FloatingGuardedNode(Stamp stamp, GuardingNode guard) { + super(stamp); + this.guard = guard; + } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } + + @Override + public FloatingNode asNode() { + return this; + } + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -42,14 +42,14 @@ * control flow would have reached the guarded node (without taking exceptions into account). */ @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}") -public final class GuardNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, Negatable { +public final class GuardNode extends FloatingGuardedNode implements Canonicalizable, Node.IterableNodeType, Negatable, GuardingNode, GuardedNode { @Input private LogicNode condition; private final DeoptimizationReason reason; private final DeoptimizationAction action; private boolean negated; - public GuardNode(LogicNode condition, FixedNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated) { + public GuardNode(LogicNode condition, GuardingNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated) { super(StampFactory.dependency(), anchor); this.condition = condition; this.reason = reason; @@ -95,16 +95,15 @@ if (condition() instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition(); if (c.getValue() != negated) { - if (dependencies().size() == 1) { - return dependencies().get(0); - } + return getGuard().asNode(); } } return this; } @Override - public Negatable negate() { + public Negatable negate(LogicNode cond) { + assert cond == condition(); negated = !negated; return this; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,10 +25,14 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -39,8 +43,8 @@ */ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, Negatable { - @Successor private BeginNode trueSuccessor; - @Successor private BeginNode falseSuccessor; + @Successor private AbstractBeginNode trueSuccessor; + @Successor private AbstractBeginNode falseSuccessor; @Input private LogicNode condition; private double trueSuccessorProbability; @@ -54,15 +58,15 @@ } public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) { - this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability); + this(condition, AbstractBeginNode.begin(trueSuccessor), AbstractBeginNode.begin(falseSuccessor), trueSuccessorProbability); } - public IfNode(LogicNode condition, BeginNode trueSuccessor, BeginNode falseSuccessor, double trueSuccessorProbability) { + public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) { super(StampFactory.forVoid()); this.condition = condition; this.falseSuccessor = falseSuccessor; - this.trueSuccessorProbability = trueSuccessorProbability; this.trueSuccessor = trueSuccessor; + setTrueSuccessorProbability(trueSuccessorProbability); } @@ -71,7 +75,7 @@ * * @return the true successor */ - public BeginNode trueSuccessor() { + public AbstractBeginNode trueSuccessor() { return trueSuccessor; } @@ -80,16 +84,16 @@ * * @return the false successor */ - public BeginNode falseSuccessor() { + public AbstractBeginNode falseSuccessor() { return falseSuccessor; } - public void setTrueSuccessor(BeginNode node) { + public void setTrueSuccessor(AbstractBeginNode node) { updatePredecessor(trueSuccessor, node); trueSuccessor = node; } - public void setFalseSuccessor(BeginNode node) { + public void setFalseSuccessor(AbstractBeginNode node) { updatePredecessor(falseSuccessor, node); falseSuccessor = node; } @@ -100,28 +104,30 @@ * @param istrue {@code true} if the true successor is requested, {@code false} otherwise * @return the corresponding successor */ - public BeginNode successor(boolean istrue) { + public AbstractBeginNode successor(boolean istrue) { return istrue ? trueSuccessor : falseSuccessor; } @Override - public Negatable negate() { - BeginNode trueSucc = trueSuccessor(); - BeginNode falseSucc = falseSuccessor(); + public Negatable negate(LogicNode cond) { + assert cond == condition(); + AbstractBeginNode trueSucc = trueSuccessor(); + AbstractBeginNode falseSucc = falseSuccessor(); setTrueSuccessor(null); setFalseSuccessor(null); setTrueSuccessor(falseSucc); setFalseSuccessor(trueSucc); - trueSuccessorProbability = 1 - trueSuccessorProbability; + setTrueSuccessorProbability(1 - trueSuccessorProbability); return this; } public void setTrueSuccessorProbability(double prob) { - trueSuccessorProbability = prob; + assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob; + trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob)); } @Override - public double probability(BeginNode successor) { + public double probability(AbstractBeginNode successor) { return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability; } @@ -145,35 +151,193 @@ if (c.getValue()) { tool.deleteBranch(falseSuccessor()); tool.addToWorkList(trueSuccessor()); - ((StructuredGraph) graph()).removeSplit(this, trueSuccessor()); + graph().removeSplit(this, trueSuccessor()); + return; } else { tool.deleteBranch(trueSuccessor()); tool.addToWorkList(falseSuccessor()); - ((StructuredGraph) graph()).removeSplit(this, falseSuccessor()); + graph().removeSplit(this, falseSuccessor()); + return; + } + } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) { + + if (removeOrMaterializeIf(tool)) { + return; } - } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) { - if (!removeOrMaterializeIf(tool)) { - removeIntermediateMaterialization(tool); + } + + if (removeIntermediateMaterialization(tool)) { + return; + } + + if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) { + AbstractBeginNode intermediateBegin = falseSuccessor(); + IfNode nextIf = (IfNode) intermediateBegin.next(); + double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability; + if (this.trueSuccessorProbability < probabilityB) { + // Reordering of those two if statements is beneficial from the point of view of + // their probabilities. + if (prepareForSwap(tool.runtime(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) { + // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1). + assert intermediateBegin.next() == nextIf; + AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor(); + nextIf.setFalseSuccessor(null); + intermediateBegin.setNext(null); + this.setFalseSuccessor(null); + + this.replaceAtPredecessor(nextIf); + nextIf.setFalseSuccessor(intermediateBegin); + intermediateBegin.setNext(this); + this.setFalseSuccessor(bothFalseBegin); + nextIf.setTrueSuccessorProbability(probabilityB); + if (probabilityB == 1.0) { + this.setTrueSuccessorProbability(0.0); + } else { + double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB); + this.setTrueSuccessorProbability(Math.min(1.0, newProbability)); + } + return; + } } } } + private static boolean prepareForSwap(MetaAccessProvider runtime, LogicNode a, LogicNode b, double probabilityA, double probabilityB) { + if (a instanceof InstanceOfNode) { + InstanceOfNode instanceOfA = (InstanceOfNode) a; + if (b instanceof IsNullNode) { + IsNullNode isNullNode = (IsNullNode) b; + if (isNullNode.object() == instanceOfA.object()) { + if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) { + instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes())); + } + Debug.log("Can swap instanceof and isnull if"); + return true; + } + } else if (b instanceof InstanceOfNode) { + InstanceOfNode instanceOfB = (InstanceOfNode) b; + if (instanceOfA.object() == instanceOfB.object() && !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) { + // Two instanceof on the same value with mutually exclusive types. + JavaTypeProfile profileA = instanceOfA.profile(); + JavaTypeProfile profileB = instanceOfB.profile(); + + Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type()); + JavaTypeProfile newProfile = null; + if (profileA != null && profileB != null) { + double remainder = 1.0; + ArrayList profiledTypes = new ArrayList<>(); + for (ProfiledType type : profileB.getTypes()) { + if (instanceOfB.type().isAssignableFrom(type.getType())) { + // Do not add to profile. + } else { + ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() * (1.0 - probabilityA) / (1.0 - probabilityB))); + profiledTypes.add(newType); + remainder -= newType.getProbability(); + } + } + + for (ProfiledType type : profileA.getTypes()) { + if (instanceOfA.type().isAssignableFrom(type.getType())) { + ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() / (1.0 - probabilityB))); + profiledTypes.add(newType); + remainder -= newType.getProbability(); + } + } + Collections.sort(profiledTypes); + + if (remainder < 0.0) { + // Can happen due to round-off errors. + remainder = 0.0; + } + newProfile = new JavaTypeProfile(profileB.getNullSeen(), remainder, profiledTypes.toArray(new ProfiledType[profiledTypes.size()])); + Debug.log("First profile: %s", profileA); + Debug.log("Original second profile: %s", profileB); + Debug.log("New second profile: %s", newProfile); + } + instanceOfB.setProfile(profileA); + instanceOfA.setProfile(newProfile); + return true; + } + } + } else if (a instanceof CompareNode) { + CompareNode compareA = (CompareNode) a; + Condition conditionA = compareA.condition(); + if (compareA.unorderedIsTrue()) { + return false; + } + if (b instanceof CompareNode) { + CompareNode compareB = (CompareNode) b; + if (compareA == compareB) { + Debug.log("Same conditions => do not swap and leave the work for global value numbering."); + return false; + } + if (compareB.unorderedIsTrue()) { + return false; + } + Condition comparableCondition = null; + Condition conditionB = compareB.condition(); + if (compareB.x() == compareA.x() && compareB.y() == compareA.y()) { + comparableCondition = conditionB; + } else if (compareB.x() == compareA.y() && compareB.y() == compareA.x()) { + comparableCondition = conditionB.mirror(); + } + + if (comparableCondition != null) { + Condition combined = conditionA.join(comparableCondition); + if (combined == null) { + // The two conditions are disjoint => can reorder. + Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition); + return true; + } + } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) { + boolean canSwap = false; + if ((compareA.x() == compareB.x() && valuesDistinct(runtime, compareA.y(), compareB.y()))) { + canSwap = true; + } else if ((compareA.x() == compareB.y() && valuesDistinct(runtime, compareA.y(), compareB.x()))) { + canSwap = true; + } else if ((compareA.y() == compareB.x() && valuesDistinct(runtime, compareA.x(), compareB.y()))) { + canSwap = true; + } else if ((compareA.y() == compareB.y() && valuesDistinct(runtime, compareA.x(), compareB.x()))) { + canSwap = true; + } + + if (canSwap) { + Debug.log("Can swap equality condition with one shared and one disjoint value."); + return true; + } + } + } + } + + return false; + } + + private static boolean valuesDistinct(MetaAccessProvider runtime, ValueNode a, ValueNode b) { + if (a.isConstant() && b.isConstant()) { + return !runtime.constantEquals(a.asConstant(), b.asConstant()); + } + + Stamp stampA = a.stamp(); + Stamp stampB = b.stamp(); + return stampA.alwaysDistinct(stampB); + } + /** * Tries to remove an empty if construct or replace an if construct with a materialization. * * @return true if a transformation was made, false otherwise */ private boolean removeOrMaterializeIf(SimplifierTool tool) { - if (trueSuccessor().next() instanceof EndNode && falseSuccessor().next() instanceof EndNode) { - EndNode trueEnd = (EndNode) trueSuccessor().next(); - EndNode falseEnd = (EndNode) falseSuccessor().next(); + if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) { + AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next(); + AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next(); MergeNode merge = trueEnd.merge(); if (merge == falseEnd.merge() && merge.forwardEndCount() == 2 && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) { Iterator phis = merge.phis().iterator(); if (!phis.hasNext()) { // empty if construct with no phis: remove it removeEmptyIf(tool); - return false; + return true; } else { PhiNode singlePhi = phis.next(); if (!phis.hasNext()) { @@ -190,7 +354,7 @@ } if (trueValue.isConstant() && falseValue.isConstant()) { ConditionalNode materialize = graph().unique(new ConditionalNode(condition(), trueValue, falseValue)); - ((StructuredGraph) graph()).replaceFloating(singlePhi, materialize); + graph().replaceFloating(singlePhi, materialize); removeEmptyIf(tool); return true; } @@ -260,11 +424,12 @@ return false; } - MergeNode merge = (MergeNode) predecessor(); - if (!merge.anchored().isEmpty()) { + if (predecessor() instanceof LoopBeginNode) { return false; } + MergeNode merge = (MergeNode) predecessor(); + // Only consider merges with a single usage that is both a phi and an operand of the // comparison NodeIterable mergeUsages = merge.usages(); @@ -288,11 +453,8 @@ } } - List mergePredecessors = merge.cfgPredecessors().snapshot(); - if (phi.valueCount() != merge.forwardEndCount()) { - // Handles a loop begin merge - return false; - } + List mergePredecessors = merge.cfgPredecessors().snapshot(); + assert phi.valueCount() == merge.forwardEndCount(); Constant[] xs = constantValues(compare.x(), merge); Constant[] ys = constantValues(compare.y(), merge); @@ -300,19 +462,24 @@ return false; } - List falseEnds = new ArrayList<>(mergePredecessors.size()); - List trueEnds = new ArrayList<>(mergePredecessors.size()); - Map phiValues = new HashMap<>(mergePredecessors.size()); + // Sanity check that both ends are not followed by a merge without frame state. + if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) { + return false; + } - BeginNode oldFalseSuccessor = falseSuccessor(); - BeginNode oldTrueSuccessor = trueSuccessor(); + List falseEnds = new ArrayList<>(mergePredecessors.size()); + List trueEnds = new ArrayList<>(mergePredecessors.size()); + Map phiValues = new HashMap<>(mergePredecessors.size()); + + AbstractBeginNode oldFalseSuccessor = falseSuccessor(); + AbstractBeginNode oldTrueSuccessor = trueSuccessor(); setFalseSuccessor(null); setTrueSuccessor(null); - Iterator ends = mergePredecessors.iterator(); + Iterator ends = mergePredecessors.iterator(); for (int i = 0; i < xs.length; i++) { - EndNode end = ends.next(); + AbstractEndNode end = ends.next(); phiValues.put(end, phi.valueAt(end)); if (compare.condition().foldCondition(xs[i], ys[i], tool.runtime(), compare.unorderedIsTrue())) { trueEnds.add(end); @@ -336,6 +503,45 @@ return true; } + private static boolean checkFrameState(FixedNode start) { + FixedNode node = start; + while (true) { + if (node instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) node; + if (mergeNode.stateAfter() == null) { + return false; + } else { + return true; + } + } else if (node instanceof StateSplit) { + StateSplit stateSplitNode = (StateSplit) node; + if (stateSplitNode.stateAfter() != null) { + return true; + } + } + + if (node instanceof ControlSplitNode) { + ControlSplitNode controlSplitNode = (ControlSplitNode) node; + for (Node succ : controlSplitNode.cfgSuccessors()) { + if (checkFrameState((FixedNode) succ)) { + return true; + } + } + return false; + } else if (node instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; + node = fixedWithNextNode.next(); + } else if (node instanceof AbstractEndNode) { + AbstractEndNode endNode = (AbstractEndNode) node; + node = endNode.merge(); + } else if (node instanceof ControlSinkNode) { + return true; + } else { + return false; + } + } + } + /** * Connects a set of ends to a given successor, inserting a merge node if there is more than one * end. If {@code ends} is empty, then {@code successor} is @@ -345,12 +551,12 @@ * @param oldMerge the merge being removed * @param phiValues the values of the phi at the merge, keyed by the merge ends */ - private void connectEnds(List ends, Map phiValues, BeginNode successor, MergeNode oldMerge, SimplifierTool tool) { + private void connectEnds(List ends, Map phiValues, AbstractBeginNode successor, MergeNode oldMerge, SimplifierTool tool) { if (ends.isEmpty()) { GraphUtil.killCFG(successor); } else { if (ends.size() == 1) { - EndNode end = ends.get(0); + AbstractEndNode end = ends.get(0); ((FixedWithNextNode) end.predecessor()).setNext(successor); oldMerge.removeEnd(end); GraphUtil.killCFG(end); @@ -361,7 +567,7 @@ PhiNode oldPhi = (PhiNode) oldMerge.usages().first(); PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge)); - for (EndNode end : ends) { + for (AbstractEndNode end : ends) { newPhi.addInput(phiValues.get(end)); newMerge.addForwardEnd(end); } @@ -413,12 +619,12 @@ } private void removeEmptyIf(SimplifierTool tool) { - BeginNode originalTrueSuccessor = trueSuccessor(); - BeginNode originalFalseSuccessor = falseSuccessor(); - assert originalTrueSuccessor.next() instanceof EndNode && originalFalseSuccessor.next() instanceof EndNode; + AbstractBeginNode originalTrueSuccessor = trueSuccessor(); + AbstractBeginNode originalFalseSuccessor = falseSuccessor(); + assert originalTrueSuccessor.next() instanceof AbstractEndNode && originalFalseSuccessor.next() instanceof AbstractEndNode; - EndNode trueEnd = (EndNode) originalTrueSuccessor.next(); - EndNode falseEnd = (EndNode) originalFalseSuccessor.next(); + AbstractEndNode trueEnd = (AbstractEndNode) originalTrueSuccessor.next(); + AbstractEndNode falseEnd = (AbstractEndNode) originalFalseSuccessor.next(); assert trueEnd.merge() == falseEnd.merge(); FixedWithNextNode pred = (FixedWithNextNode) predecessor(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Mon May 13 17:11:31 2013 +0200 @@ -23,9 +23,10 @@ package com.oracle.graal.nodes; import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; -public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode { +public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode, GuardedNode { FixedNode next(); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; @@ -38,6 +39,7 @@ @Input private final CallTargetNode callTarget; @Input private FrameState deoptState; + @Input private GuardingNode guard; private final int bci; private boolean polymorphic; private boolean useForInlining; @@ -90,8 +92,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override @@ -145,14 +147,14 @@ stateSplit.setStateAfter(stateAfter); } if (node instanceof FixedWithNextNode) { - ((StructuredGraph) graph()).replaceFixedWithFixed(this, (FixedWithNextNode) node); - } else if (node instanceof DeoptimizeNode) { + graph().replaceFixedWithFixed(this, (FixedWithNextNode) node); + } else if (node instanceof ControlSinkNode) { this.replaceAtPredecessor(node); this.replaceAtUsages(null); GraphUtil.killCFG(this); return; } else { - ((StructuredGraph) graph()).replaceFixed(this, node); + graph().replaceFixed(this, node); } call.safeDelete(); if (stateAfter.usages().isEmpty()) { @@ -189,4 +191,15 @@ public boolean isCallSiteDeoptimization() { return true; } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; @@ -34,11 +35,12 @@ @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}") public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint, LIRLowerable { - @Successor private BeginNode next; + @Successor private AbstractBeginNode next; @Successor private DispatchBeginNode exceptionEdge; @Input private final CallTargetNode callTarget; @Input private FrameState deoptState; @Input private FrameState stateAfter; + @Input private GuardingNode guard; private final int bci; private boolean polymorphic; private boolean useForInlining; @@ -61,11 +63,11 @@ exceptionEdge = x; } - public BeginNode next() { + public AbstractBeginNode next() { return next; } - public void setNext(BeginNode x) { + public void setNext(AbstractBeginNode x) { updatePredecessor(next, x); next = x; } @@ -121,7 +123,7 @@ @Override public void setNext(FixedNode x) { if (x != null) { - this.setNext(BeginNode.begin(x)); + this.setNext(AbstractBeginNode.begin(x)); } else { this.setNext(null); } @@ -151,8 +153,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } public FrameState stateDuring() { @@ -170,7 +172,7 @@ } public void killExceptionEdge() { - BeginNode edge = exceptionEdge(); + AbstractBeginNode edge = exceptionEdge(); setExceptionEdge(null); GraphUtil.killCFG(edge); } @@ -187,14 +189,14 @@ } if (node == null) { assert kind() == Kind.Void && usages().isEmpty(); - ((StructuredGraph) graph()).removeSplit(this, next()); - } else if (node instanceof DeoptimizeNode) { + graph().removeSplit(this, next()); + } else if (node instanceof ControlSinkNode) { this.replaceAtPredecessor(node); this.replaceAtUsages(null); GraphUtil.killCFG(this); return; } else { - ((StructuredGraph) graph()).replaceSplit(this, node, next()); + graph().replaceSplit(this, node, next()); } call.safeDelete(); if (state.usages().isEmpty()) { @@ -205,7 +207,7 @@ private static final double EXCEPTION_PROBA = 1e-5; @Override - public double probability(BeginNode successor) { + public double probability(AbstractBeginNode successor) { return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA; } @@ -238,4 +240,15 @@ public boolean isCallSiteDeoptimization() { return true; } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LocalNode.java Mon May 13 17:11:31 2013 +0200 @@ -23,37 +23,15 @@ package com.oracle.graal.nodes; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; /** * The {@code Local} instruction is a placeholder for an incoming argument to a function call. */ @NodeInfo(nameTemplate = "Local({p#index})") -public final class LocalNode extends FloatingNode implements Node.IterableNodeType { - - private final int index; +public final class LocalNode extends AbstractLocalNode implements Node.IterableNodeType { public LocalNode(int index, Stamp stamp) { - super(stamp); - this.index = index; - } - - /** - * Gets the index of this local in the array of parameters. This is NOT the JVM local index. - * - * @return the index - */ - public int index() { - return index; - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "(" + index + ")"; - } else { - return super.toString(verbosity); - } + super(index, stamp); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicBinaryNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicBinaryNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.spi.*; + +public abstract class LogicBinaryNode extends LogicNode implements Negatable, Node.IterableNodeType { + + @Input private LogicNode x; + @Input private LogicNode y; + private boolean xNegated; + private boolean yNegated; + + public LogicBinaryNode(LogicNode x, LogicNode y) { + this(x, false, y, false); + } + + public LogicBinaryNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) { + this.x = x; + this.xNegated = xNegated; + this.y = y; + this.yNegated = yNegated; + } + + public LogicNode getX() { + return x; + } + + public LogicNode getY() { + return y; + } + + public boolean isXNegated() { + return xNegated; + } + + public boolean isYNegated() { + return yNegated; + } + + @Override + public Negatable negate(LogicNode condition) { + if (condition == x) { + xNegated = !xNegated; + } + if (condition == y) { + yNegated = !yNegated; + } + return this; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConjunctionNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConjunctionNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.nodes.spi.*; + +/** + * This node is true if {@link #getX() x} and {@link #getY() y} are true. + * + */ +public class LogicConjunctionNode extends LogicBinaryNode implements Canonicalizable { + + public LogicConjunctionNode(LogicNode x, LogicNode y) { + this(x, false, y, false); + } + + public LogicConjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) { + super(x, xNegated, y, yNegated); + } + + @Override + public LogicNode canonical(CanonicalizerTool tool) { + LogicNode x = getX(); + LogicNode y = getY(); + if (x == y) { + return x; + } + if (x instanceof LogicConstantNode) { + if (((LogicConstantNode) x).getValue() ^ isXNegated()) { + if (isYNegated()) { + negateUsages(); + } + return y; + } else { + return LogicConstantNode.contradiction(graph()); + } + } + if (y instanceof LogicConstantNode) { + if (((LogicConstantNode) y).getValue() ^ isYNegated()) { + if (isXNegated()) { + negateUsages(); + } + return x; + } else { + return LogicConstantNode.contradiction(graph()); + } + } + return this; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicDisjunctionNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicDisjunctionNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.nodes.spi.*; + +/** + * This node is true if {@link #getX() x} or {@link #getY() y} are true. + * + */ +public class LogicDisjunctionNode extends LogicBinaryNode implements Canonicalizable { + + public LogicDisjunctionNode(LogicNode x, LogicNode y) { + this(x, false, y, false); + } + + public LogicDisjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) { + super(x, xNegated, y, yNegated); + } + + @Override + public LogicNode canonical(CanonicalizerTool tool) { + LogicNode x = getX(); + LogicNode y = getY(); + if (x == y) { + return x; + } + if (x instanceof LogicConstantNode) { + if (((LogicConstantNode) x).getValue() ^ isXNegated()) { + return LogicConstantNode.tautology(graph()); + } else { + if (isYNegated()) { + negateUsages(); + } + return y; + } + } + if (y instanceof LogicConstantNode) { + if (((LogicConstantNode) y).getValue() ^ isYNegated()) { + return LogicConstantNode.tautology(graph()); + } else { + if (isXNegated()) { + negateUsages(); + } + return x; + } + } + return this; + } + +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java Mon May 13 17:11:31 2013 +0200 @@ -29,8 +29,8 @@ public abstract class LogicNode extends FloatingNode { - public LogicNode(ValueNode... dependencies) { - super(StampFactory.condition(), dependencies); + public LogicNode() { + super(StampFactory.condition()); } /** @@ -40,7 +40,7 @@ public void negateUsages() { for (Node n : usages().snapshot()) { assert n instanceof Negatable; - ((Negatable) n).negate(); + ((Negatable) n).negate(this); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Mon May 13 17:11:31 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; public class LoopBeginNode extends MergeNode implements Node.IterableNodeType, LIRLowerable { @@ -35,6 +36,7 @@ private double loopFrequency; private int nextEndIndex; private int unswitches; + @Input private GuardingNode overflowGuard; public LoopBeginNode() { loopFrequency = 1; @@ -87,7 +89,7 @@ return snapshot; } - public EndNode forwardEnd() { + public AbstractEndNode forwardEnd() { assert forwardEndCount() == 1; return forwardEndAt(0); } @@ -98,7 +100,7 @@ } @Override - protected void deleteEnd(EndNode end) { + protected void deleteEnd(AbstractEndNode end) { if (end instanceof LoopEndNode) { LoopEndNode loopEnd = (LoopEndNode) end; loopEnd.setLoopBegin(null); @@ -122,7 +124,7 @@ } @Override - public int phiPredecessorIndex(EndNode pred) { + public int phiPredecessorIndex(AbstractEndNode pred) { if (pred instanceof LoopEndNode) { LoopEndNode loopEnd = (LoopEndNode) pred; if (loopEnd.loopBegin() == this) { @@ -136,7 +138,7 @@ } @Override - public EndNode phiPredecessorAt(int index) { + public AbstractEndNode phiPredecessorAt(int index) { if (index < forwardEndCount()) { return forwardEndAt(index); } @@ -173,15 +175,23 @@ // nothing yet } - public boolean isLoopExit(BeginNode begin) { + public boolean isLoopExit(AbstractBeginNode begin) { return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this; } public void removeExits() { - StructuredGraph graph = (StructuredGraph) graph(); for (LoopExitNode loopexit : loopExits().snapshot()) { loopexit.removeProxies(); - graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode())); + graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode())); } } + + public GuardingNode getOverflowGuard() { + return overflowGuard; + } + + public void setOverflowGuard(GuardingNode overflowGuard) { + updateUsages(this.overflowGuard == null ? null : this.overflowGuard.asNode(), overflowGuard == null ? null : overflowGuard.asNode()); + this.overflowGuard = overflowGuard; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; -public final class LoopEndNode extends EndNode { +public final class LoopEndNode extends AbstractEndNode { @Input(notDataflow = true) private LoopBeginNode loopBegin; private boolean canSafepoint; @@ -60,9 +60,6 @@ } public boolean canSafepoint() { - if (!canSafepoint) { - return canSafepoint; - } return canSafepoint; } @@ -81,7 +78,7 @@ /** * Returns the 0-based index of this loop end. This is not the index into {@link PhiNode} - * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(EndNode)} for this + * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(AbstractEndNode)} for this * purpose. * * @return The 0-based index of this loop end. diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Mon May 13 17:11:31 2013 +0200 @@ -35,18 +35,18 @@ */ public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable { - @Input(notDataflow = true) private final NodeInputList ends = new NodeInputList<>(this); + @Input(notDataflow = true) private final NodeInputList ends = new NodeInputList<>(this); @Override public void generate(LIRGeneratorTool gen) { gen.visitMerge(this); } - public int forwardEndIndex(EndNode end) { + public int forwardEndIndex(AbstractEndNode end) { return ends.indexOf(end); } - public void addForwardEnd(EndNode end) { + public void addForwardEnd(AbstractEndNode end) { ends.add(end); } @@ -54,12 +54,12 @@ return ends.size(); } - public EndNode forwardEndAt(int index) { + public AbstractEndNode forwardEndAt(int index) { return ends.get(index); } @Override - public NodeIterable cfgPredecessors() { + public NodeIterable cfgPredecessors() { return ends; } @@ -79,7 +79,7 @@ * * @param pred the end to remove */ - public void removeEnd(EndNode pred) { + public void removeEnd(AbstractEndNode pred) { int predIndex = phiPredecessorIndex(pred); assert predIndex != -1; deleteEnd(pred); @@ -95,7 +95,7 @@ } } - protected void deleteEnd(EndNode end) { + protected void deleteEnd(AbstractEndNode end) { ends.remove(end); } @@ -103,7 +103,7 @@ ends.clear(); } - public NodeIterable forwardEnds() { + public NodeIterable forwardEnds() { return ends; } @@ -111,11 +111,11 @@ return forwardEndCount(); } - public int phiPredecessorIndex(EndNode pred) { + public int phiPredecessorIndex(AbstractEndNode pred) { return forwardEndIndex(pred); } - public EndNode phiPredecessorAt(int index) { + public AbstractEndNode phiPredecessorAt(int index) { return forwardEndAt(index); } @@ -143,8 +143,8 @@ @Override public void simplify(SimplifierTool tool) { FixedNode next = next(); - if (next instanceof EndNode) { - EndNode origLoopEnd = (EndNode) next; + if (next instanceof AbstractEndNode) { + AbstractEndNode origLoopEnd = (AbstractEndNode) next; MergeNode merge = origLoopEnd.merge(); if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) { return; @@ -154,6 +154,10 @@ if (this.anchored().isNotEmpty()) { return; } + if (merge.stateAfter() == null && this.stateAfter() != null) { + // We hold a state, but the succeeding merge does not => do not combine. + return; + } for (PhiNode phi : phis()) { for (Node usage : phi.usages().filter(isNotA(FrameState.class))) { if (!merge.isPhiAtMerge(usage)) { @@ -163,14 +167,13 @@ } Debug.log("Split %s into ends for %s.", this, merge); int numEnds = this.forwardEndCount(); - StructuredGraph graph = (StructuredGraph) graph(); for (int i = 0; i < numEnds - 1; i++) { - EndNode end = forwardEndAt(numEnds - 1 - i); - EndNode newEnd; + AbstractEndNode end = forwardEndAt(numEnds - 1 - i); + AbstractEndNode newEnd; if (merge instanceof LoopBeginNode) { - newEnd = graph.add(new LoopEndNode((LoopBeginNode) merge)); + newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge)); } else { - newEnd = graph.add(new EndNode()); + newEnd = graph().add(new EndNode()); merge.addForwardEnd(newEnd); } for (PhiNode phi : merge.phis()) { @@ -189,7 +192,7 @@ end.safeDelete(); tool.addToWorkList(newEnd.predecessor()); // ? } - graph.reduceTrivialMerge(this); + graph().reduceTrivialMerge(this); } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -33,7 +34,7 @@ * variable. */ @NodeInfo(nameTemplate = "{p#type/s}Phi({i#values})") -public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType { +public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, GuardingNode { public static enum PhiType { Value(null), // normal value phis @@ -159,7 +160,7 @@ values.set(i, x); } - public ValueNode valueAt(EndNode pred) { + public ValueNode valueAt(AbstractEndNode pred) { return valueAt(merge().phiPredecessorIndex(pred)); } @@ -251,4 +252,9 @@ public boolean isLoopPhi() { return merge() instanceof LoopBeginNode; } + + @Override + public PhiNode asNode() { + return this; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,9 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -31,9 +32,10 @@ * A node that changes the type of its input, usually narrowing it. For example, a PI node refines * the type of a receiver during type-guarded inlining to be the type tested by the guard. */ -public class PiNode extends FloatingNode implements LIRLowerable, Virtualizable, Node.IterableNodeType { +public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode { @Input private ValueNode object; + @Input private FixedNode anchor; public ValueNode object() { return object; @@ -44,20 +46,22 @@ this.object = object; } - public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) { - super(stamp, anchor); - assert anchor instanceof FixedNode; + public PiNode(ValueNode object, Stamp stamp, FixedNode anchor) { + super(stamp); this.object = object; + this.anchor = anchor; } @Override public void generate(LIRGeneratorTool generator) { - generator.setResult(this, generator.operand(object)); + if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) { + generator.setResult(this, generator.operand(object)); + } } @Override public boolean inferStamp() { - if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) { + if (stamp() instanceof ObjectStamp && object().objectStamp().alwaysNull() && objectStamp().nonNull()) { // a null value flowing into a nonNull PiNode should be guarded by a type/isNull guard, // but the // compiler might see this situation before the branch is deleted diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Mon May 13 17:11:31 2013 +0200 @@ -37,12 +37,12 @@ @NodeInfo(nameTemplate = "{p#type/s}Proxy") public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable { - @Input(notDataflow = true) private BeginNode proxyPoint; + @Input(notDataflow = true) private AbstractBeginNode proxyPoint; @Input private ValueNode value; private final PhiType type; private final Object identity; - public ProxyNode(ValueNode value, BeginNode exit, PhiType type, Object identity) { + public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, Object identity) { super(type == PhiType.Value ? value.stamp() : type.stamp); this.type = type; this.identity = identity; @@ -65,7 +65,7 @@ return value().stamp(); } - public BeginNode proxyPoint() { + public AbstractBeginNode proxyPoint() { return proxyPoint; } @@ -108,11 +108,11 @@ } } - public static ProxyNode forValue(ValueNode value, BeginNode exit, StructuredGraph graph) { + public static ProxyNode forValue(ValueNode value, AbstractBeginNode exit, StructuredGraph graph) { return graph.unique(new ProxyNode(value, exit, PhiType.Value, null)); } - public static ProxyNode forMemory(ValueNode value, BeginNode exit, Object location, StructuredGraph graph) { + public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, Object location, StructuredGraph graph) { return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location)); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java Mon May 13 17:11:31 2013 +0200 @@ -36,4 +36,9 @@ updatePredecessor(scheduledNext, x); scheduledNext = x; } + + @Override + public StructuredGraph graph() { + return (StructuredGraph) super.graph(); + } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Mon May 13 17:11:31 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; /** * The start node of a graph. @@ -30,7 +31,7 @@ public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint { @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Mon May 13 17:11:31 2013 +0200 @@ -44,20 +44,22 @@ private final Set leafGraphIds = new HashSet<>(4); - private final StartNode start; + private StartNode start; private final ResolvedJavaMethod method; private final long graphId; private final int entryBCI; /** - * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node. + * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() + * start} node. */ public StructuredGraph() { this(null, null); } /** - * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node. + * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() + * start} node. */ public StructuredGraph(String name, ResolvedJavaMethod method) { this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI); @@ -73,7 +75,7 @@ private StructuredGraph(String name, ResolvedJavaMethod method, long graphId, int entryBCI) { super(name); - this.start = add(new StartNode()); + this.setStart(add(new StartNode())); this.method = method; this.graphId = graphId; this.entryBCI = entryBCI; @@ -104,6 +106,11 @@ return start; } + /** + * Gets the method from which this graph was built. + * + * @return null if this method was not built from a method or the method is not available + */ public ResolvedJavaMethod method() { return method; } @@ -116,6 +123,10 @@ return graphId; } + public void setStart(StartNode start) { + this.start = start; + } + /** * @return the {@link Set} that contains the {@link #graphId()} of all graphs that were * incorporated into this one (e.g. by inlining). @@ -214,8 +225,8 @@ */ public void removeFixed(FixedWithNextNode node) { assert node != null; - if (node instanceof BeginNode) { - ((BeginNode) node).prepareDelete(); + if (node instanceof AbstractBeginNode) { + ((AbstractBeginNode) node).prepareDelete(); } assert node.usages().isEmpty() : node + " " + node.usages(); FixedNode next = node.next(); @@ -240,6 +251,9 @@ node.setNext(null); replacement.setNext(next); node.replaceAndDelete(replacement); + if (node == start) { + setStart((StartNode) replacement); + } } public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) { @@ -251,7 +265,7 @@ node.safeDelete(); } - public void removeSplit(ControlSplitNode node, BeginNode survivingSuccessor) { + public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) { assert node != null; assert node.usages().isEmpty(); assert survivingSuccessor != null; @@ -260,7 +274,7 @@ node.safeDelete(); } - public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) { + public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) { assert node != null; assert node.usages().isEmpty(); assert survivingSuccessor != null; @@ -271,13 +285,13 @@ for (Node successor : snapshot) { if (successor != null && successor.isAlive()) { if (successor != survivingSuccessor) { - GraphUtil.killCFG((BeginNode) successor); + GraphUtil.killCFG((AbstractBeginNode) successor); } } } } - public void replaceSplit(ControlSplitNode node, Node replacement, BeginNode survivingSuccessor) { + public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) { if (replacement instanceof FixedWithNextNode) { replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor); } else { @@ -287,7 +301,7 @@ } } - public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, BeginNode survivingSuccessor) { + public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; assert survivingSuccessor != null; node.clearSuccessors(); @@ -295,7 +309,7 @@ node.replaceAndDelete(replacement); } - public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, BeginNode survivingSuccessor) { + public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; assert survivingSuccessor != null; node.clearSuccessors(); @@ -348,7 +362,7 @@ if (merge instanceof LoopBeginNode) { ((LoopBeginNode) merge).removeExits(); } - EndNode singleEnd = merge.forwardEndAt(0); + AbstractEndNode singleEnd = merge.forwardEndAt(0); FixedNode sux = merge.next(); FrameState stateAfter = merge.stateAfter(); // evacuateGuards diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A node that attached a type profile to a proxied input node. + */ +public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType { + + @Input private ValueNode object; + private final JavaTypeProfile profile; + private transient ResolvedJavaType lastCheckedType; + private transient JavaTypeProfile lastCheckedProfile; + + public ValueNode getObject() { + return object; + } + + public static ValueNode create(ValueNode object, JavaTypeProfile profile) { + if (profile == null) { + // No profile, so create no node. + return object; + } + if (profile.getTypes().length == 0) { + // Only null profiling is not beneficial enough to keep the node around. + return object; + } + return object.graph().add(new TypeProfileProxyNode(object, profile)); + } + + private TypeProfileProxyNode(ValueNode object, JavaTypeProfile profile) { + super(object.stamp()); + this.object = object; + this.profile = profile; + } + + public JavaTypeProfile getProfile() { + return profile; + } + + @Override + public boolean inferStamp() { + return object.inferStamp(); + } + + @Override + public Stamp stamp() { + return object.stamp(); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (object.objectStamp().isExactType()) { + // The profile is useless - we know the type! + return object; + } else if (object instanceof TypeProfileProxyNode) { + TypeProfileProxyNode other = (TypeProfileProxyNode) object; + JavaTypeProfile otherProfile = other.getProfile(); + if (otherProfile == lastCheckedProfile) { + // We have already incorporated the knowledge about this profile => abort. + return this; + } + lastCheckedProfile = otherProfile; + JavaTypeProfile newProfile = this.profile.restrict(otherProfile); + if (newProfile.equals(otherProfile)) { + // We are useless - just use the other proxy node. + Debug.log("Canonicalize with other proxy node."); + return object; + } + if (newProfile != this.profile) { + Debug.log("Improved profile via other profile."); + return TypeProfileProxyNode.create(object, newProfile); + } + } else if (object.objectStamp().type() != null) { + ResolvedJavaType type = object.objectStamp().type(); + ResolvedJavaType uniqueConcrete = type.findUniqueConcreteSubtype(); + if (uniqueConcrete != null) { + // Profile is useless => remove. + Debug.log("Profile useless, there is enough static type information available."); + return object; + } + if (type == lastCheckedType) { + // We have already incorporate the knowledge about this type => abort. + return this; + } + lastCheckedType = type; + JavaTypeProfile newProfile = this.profile.restrict(type, object.objectStamp().nonNull()); + if (newProfile != this.profile) { + Debug.log("Improved profile via static type information."); + if (newProfile.getTypes().length == 0) { + // Only null profiling is not beneficial enough to keep the node around. + return object; + } + return TypeProfileProxyNode.create(object, newProfile); + } + } + return this; + } + + public static void cleanFromGraph(StructuredGraph graph) { + for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) { + graph.replaceFloating(proxy, proxy.getObject()); + } + assert graph.getNodes(TypeProfileProxyNode.class).count() == 0; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Mon May 13 17:11:31 2013 +0200 @@ -28,8 +28,7 @@ import com.oracle.graal.nodes.type.*; /** - * Unwind takes an exception object, destroys the current stack frame and passes the exception - * object to the system's exception dispatch code. + * Unwinds the current frame to an exception handler in the caller frame. */ public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable, Node.IterableNodeType { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; @@ -42,28 +40,8 @@ */ private Stamp stamp; - @Input(notDataflow = true) private final NodeInputList dependencies; - - /** - * This collection keeps dependencies that should be observed while scheduling (guards, etc.). - */ - public NodeInputList dependencies() { - return dependencies; - } - public ValueNode(Stamp stamp) { this.stamp = stamp; - this.dependencies = new NodeInputList<>(this); - } - - public ValueNode(Stamp stamp, ValueNode... dependencies) { - this.stamp = stamp; - this.dependencies = new NodeInputList<>(this, dependencies); - } - - public ValueNode(Stamp stamp, List dependencies) { - this.stamp = stamp; - this.dependencies = new NodeInputList<>(this, dependencies); } public Stamp stamp() { @@ -177,17 +155,4 @@ assertTrue(kind() == kind().getStackKind(), "Should have a stack kind : %s", kind()); return super.verify(); } - - @Override - public Map getDebugProperties(Map map) { - Map properties = super.getDebugProperties(map); - if (!dependencies.isEmpty()) { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < dependencies.size(); i++) { - str.append(i == 0 ? "" : ", ").append(dependencies.get(i) == null ? "null" : dependencies.get(i).toString(Verbosity.Id)); - } - properties.put("dependencies", str.toString()); - } - return properties; - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Mon May 13 17:11:31 2013 +0200 @@ -101,6 +101,16 @@ return this; } + protected void setX(ValueNode x) { + updateUsages(this.x, x); + this.x = x; + } + + protected void setY(ValueNode y) { + updateUsages(this.y, y); + this.y = y; + } + protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored); } @@ -123,6 +133,14 @@ return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false); } } + if (x() instanceof ConvertNode && y() instanceof ConvertNode) { + ConvertNode convertX = (ConvertNode) x(); + ConvertNode convertY = (ConvertNode) y(); + if (convertX.opcode.isLossless() && convertY.opcode.isLossless()) { + setX(convertX.value()); + setY(convertY.value()); + } + } return this; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Mon May 13 17:11:31 2013 +0200 @@ -94,9 +94,10 @@ } @Override - public Negatable negate() { + public Negatable negate(LogicNode cond) { + assert condition() == cond; ConditionalNode replacement = graph().unique(new ConditionalNode(condition, falseValue(), trueValue())); - ((StructuredGraph) graph()).replaceFloating(this, replacement); + graph().replaceFloating(this, replacement); return replacement; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,6 +25,7 @@ import static com.oracle.graal.api.meta.Kind.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -34,34 +35,97 @@ */ public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable, Lowerable { - public enum Op { - I2L(Int, Long), - L2I(Long, Int), - I2B(Int, Byte), - I2C(Int, Char), - I2S(Int, Short), - F2D(Float, Double), - D2F(Double, Float), - I2F(Int, Float), - I2D(Int, Double), - F2I(Float, Int), - D2I(Double, Int), - L2F(Long, Float), - L2D(Long, Double), - F2L(Float, Long), - D2L(Double, Long), - UNSIGNED_I2L(Int, Long), - MOV_I2F(Int, Float), - MOV_L2D(Long, Double), - MOV_F2I(Float, Int), - MOV_D2L(Double, Long); + public static enum Op { + I2L(Int, Long, true), + L2I(Long, Int, false), + I2B(Int, Byte, false), + I2C(Int, Char, false), + I2S(Int, Short, false), + F2D(Float, Double, true), + D2F(Double, Float, false), + I2F(Int, Float, false), + I2D(Int, Double, true), + F2I(Float, Int, false), + D2I(Double, Int, false), + L2F(Long, Float, false), + L2D(Long, Double, false), + F2L(Float, Long, false), + D2L(Double, Long, false), + UNSIGNED_I2L(Int, Long, true), + MOV_I2F(Int, Float, false), + MOV_L2D(Long, Double, false), + MOV_F2I(Float, Int, false), + MOV_D2L(Double, Long, false); public final Kind from; public final Kind to; + public final boolean lossless; - private Op(Kind from, Kind to) { + private Op(Kind from, Kind to, boolean lossless) { this.from = from; this.to = to; + this.lossless = lossless; + } + + public boolean isLossless() { + return lossless; + } + + public static Op getOp(Kind from, Kind to) { + switch (from) { + case Int: + switch (to) { + case Byte: + return I2B; + case Char: + return I2C; + case Short: + return I2S; + case Long: + return I2L; + case Float: + return I2F; + case Double: + return I2D; + default: + throw GraalInternalError.shouldNotReachHere(); + } + case Long: + switch (to) { + case Int: + return L2I; + case Float: + return L2F; + case Double: + return L2D; + default: + throw GraalInternalError.shouldNotReachHere(); + } + case Float: + switch (to) { + case Int: + return F2I; + case Long: + return F2L; + case Double: + return F2D; + default: + throw GraalInternalError.shouldNotReachHere(); + } + case Double: + switch (to) { + case Int: + return D2I; + case Long: + return D2L; + case Float: + return D2F; + default: + throw GraalInternalError.shouldNotReachHere(); + } + default: + throw GraalInternalError.shouldNotReachHere(); + } } } @@ -171,6 +235,14 @@ gen.setResult(this, gen.emitConvert(opcode, gen.operand(value()))); } + public static ValueNode convert(Kind toKind, ValueNode value) { + Kind fromKind = value.kind(); + if (fromKind == toKind) { + return value; + } + return value.graph().unique(new ConvertNode(Op.getOp(fromKind, toKind), value)); + } + @NodeIntrinsic public static native float convert(@ConstantNodeParameter Op op, int value); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.calc; -import java.util.*; - import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -33,12 +31,4 @@ public FloatingNode(Stamp stamp) { super(stamp); } - - public FloatingNode(Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - } - - public FloatingNode(Stamp stamp, List dependencies) { - super(stamp, dependencies); - } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Mon May 13 17:11:31 2013 +0200 @@ -99,6 +99,13 @@ } } + if (next() instanceof IntegerDivNode) { + NodeClass nodeClass = NodeClass.get(this.getClass()); + if (next().getClass() == this.getClass() && nodeClass.inputsEqual(this, next()) && nodeClass.valueEqual(this, next())) { + return next(); + } + } + return this; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Mon May 13 17:11:31 2013 +0200 @@ -83,12 +83,13 @@ @Override public boolean push(PiNode parent) { ObjectStamp piStamp = parent.objectStamp(); - ObjectStamp piValueStamp = parent.object().objectStamp(); - if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) { - replaceFirstInput(parent, parent.object()); - return true; - } else { - return false; + if (parent.object().kind() == Kind.Object) { + ObjectStamp piValueStamp = parent.object().objectStamp(); + if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) { + replaceFirstInput(parent, parent.object()); + return true; + } } + return false; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Mon May 13 17:11:31 2013 +0200 @@ -69,6 +69,10 @@ if (x() instanceof NegateNode) { return ((NegateNode) x()).x(); } + if (x() instanceof IntegerSubNode) { + IntegerSubNode sub = (IntegerSubNode) x; + return IntegerArithmeticNode.sub(sub.y(), sub.x()); + } return this; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Mon May 13 17:11:31 2013 +0200 @@ -49,21 +49,19 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - StructuredGraph graph = (StructuredGraph) graph(); - LogicNode equalComp; LogicNode lessComp; if (x().kind() == Kind.Double || x().kind() == Kind.Float) { - equalComp = graph.unique(new FloatEqualsNode(x(), y())); - lessComp = graph.unique(new FloatLessThanNode(x(), y(), isUnorderedLess)); + equalComp = graph().unique(new FloatEqualsNode(x(), y())); + lessComp = graph().unique(new FloatLessThanNode(x(), y(), isUnorderedLess)); } else { - equalComp = graph.unique(new IntegerEqualsNode(x(), y())); - lessComp = graph.unique(new IntegerLessThanNode(x(), y())); + equalComp = graph().unique(new IntegerEqualsNode(x(), y())); + lessComp = graph().unique(new IntegerLessThanNode(x(), y())); } - ConditionalNode equalValue = graph.unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph), ConstantNode.forInt(1, graph))); - ConditionalNode value = graph.unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph), equalValue)); + ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph()))); + ConditionalNode value = graph().unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph()), equalValue)); - graph.replaceFloating(this, value); + graph().replaceFloating(this, value); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Mon May 13 17:11:31 2013 +0200 @@ -70,6 +70,20 @@ return super.canonical(tool); } + private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) { + if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) { + if (other.isConstant()) { + int expectedValue = ((Boolean) other.asConstant().asObject()) ? 1 : 0; + IntegerEqualsNode equals = new IntegerEqualsNode(state.getEntry(0), ConstantNode.forInt(expectedValue, graph())); + tool.addNode(equals); + tool.replaceWithValue(equals); + } + } else { + // one of them is virtual: they can never be the same objects + tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + } + } + @Override public void virtualize(VirtualizerTool tool) { State stateX = tool.getObjectState(x()); @@ -77,9 +91,10 @@ boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual; boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual; - if (xVirtual ^ yVirtual) { - // one of them is virtual: they can never be the same objects - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + if (xVirtual && !yVirtual) { + virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : y(), tool); + } else if (!xVirtual && yVirtual) { + virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : x(), tool); } else if (xVirtual && yVirtual) { boolean xIdentity = stateX.getVirtualObject().hasIdentity(); boolean yIdentity = stateY.getVirtualObject().hasIdentity(); @@ -97,14 +112,8 @@ assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1; assert stateX.getVirtualObject().type() == stateY.getVirtualObject().type(); assert stateX.getVirtualObject().entryKind(0) == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long; - final IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0)); - tool.customAction(new Runnable() { - - @Override - public void run() { - graph().add(equals); - } - }); + IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0)); + tool.addNode(equals); tool.replaceWithValue(equals); } else { // both are virtual with identity: check if they refer to the same object diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,7 @@ public final class Block { - protected final BeginNode beginNode; + protected final AbstractBeginNode beginNode; protected int id; @@ -46,7 +46,7 @@ private boolean align; private int linearScanNumber; - protected Block(BeginNode node) { + protected Block(AbstractBeginNode node) { this.beginNode = node; this.id = ControlFlowGraph.BLOCK_ID_INITIAL; @@ -57,7 +57,7 @@ return id; } - public BeginNode getBeginNode() { + public AbstractBeginNode getBeginNode() { return beginNode; } @@ -150,7 +150,7 @@ } else { cur = ((FixedWithNextNode) cur).next(); } - assert !(cur instanceof BeginNode); + assert !(cur instanceof AbstractBeginNode); return result; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.cfg; +import java.util.*; + public class CFGVerifier { public static boolean verify(ControlFlowGraph cfg) { @@ -48,6 +50,36 @@ assert dominated.getDominator() == block; } + Block postDominatorBlock = block.getPostdominator(); + if (postDominatorBlock != null) { + assert block.getSuccessorCount() > 0 : "block has post-dominator block, but no successors"; + + BlockMap visitedBlocks = new BlockMap<>(cfg); + visitedBlocks.put(block, true); + + Deque stack = new ArrayDeque<>(); + for (Block sux : block.getSuccessors()) { + visitedBlocks.put(sux, true); + stack.push(sux); + } + + while (stack.size() > 0) { + Block tos = stack.pop(); + assert tos.getId() <= postDominatorBlock.getId(); + if (tos == postDominatorBlock) { + continue; // found a valid path + } + assert tos.getSuccessorCount() > 0 : "no path found"; + + for (Block sux : tos.getSuccessors()) { + if (visitedBlocks.get(sux) == null) { + visitedBlocks.put(sux, true); + stack.push(sux); + } + } + } + } + assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Mon May 13 17:11:31 2013 +0200 @@ -52,13 +52,14 @@ if (computePostdominators) { cfg.computePostdominators(); } - assert CFGVerifier.verify(cfg); + // there's not much to verify when connectBlocks == false + assert !(connectBlocks || computeLoops || computeDominators || computePostdominators) || CFGVerifier.verify(cfg); return cfg; } protected ControlFlowGraph(StructuredGraph graph) { this.graph = graph; - this.nodeToBlock = graph.createNodeMap(); + this.nodeToBlock = graph.createNodeMap(true); } public Block[] getBlocks() { @@ -135,7 +136,7 @@ last = cur; cur = cur.successors().first(); - } while (cur != null && !(cur instanceof BeginNode)); + } while (cur != null && !(cur instanceof AbstractBeginNode)); block.endNode = (FixedNode) last; } @@ -144,8 +145,8 @@ // Find all block headers int numBlocks = 0; for (Node node : graph.getNodes()) { - if (node instanceof BeginNode) { - Block block = new Block((BeginNode) node); + if (node instanceof AbstractBeginNode) { + Block block = new Block((AbstractBeginNode) node); numBlocks++; identifyBlock(block); } @@ -247,7 +248,7 @@ for (Block b : loop.blocks) { for (Block sux : b.getSuccessors()) { if (sux.loop != loop) { - BeginNode begin = sux.getBeginNode(); + AbstractBeginNode begin = sux.getBeginNode(); if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux); unexpected.add(sux); @@ -335,21 +336,29 @@ } private void computePostdominators() { - for (Block block : postOrder()) { + outer: for (Block block : postOrder()) { if (block.isLoopEnd()) { // We do not want the loop header registered as the postdominator of the loop end. continue; } - Block postdominator = null; + if (block.getSuccessorCount() == 0) { + // No successors => no postdominator. + continue; + } + Block firstSucc = block.getSuccessors().get(0); + if (block.getSuccessorCount() == 1) { + block.postdominator = firstSucc; + continue; + } + Block postdominator = firstSucc; for (Block sux : block.getSuccessors()) { - if (sux.isExceptionEntry()) { - // We ignore exception handlers. - } else if (postdominator == null) { - postdominator = sux; - } else { - postdominator = commonPostdominator(postdominator, sux); + postdominator = commonPostdominator(postdominator, sux); + if (postdominator == null) { + // There is a dead end => no postdominator available. + continue outer; } } + assert !block.getSuccessors().contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator; block.postdominator = postdominator; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Mon May 13 17:11:31 2013 +0200 @@ -150,27 +150,26 @@ if (!enabled) { throw new GraalInternalError("counter nodes shouldn't exist when not enabled"); } - StructuredGraph graph = (StructuredGraph) graph(); - if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { - int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); + if (excludedClassPrefix == null || !graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { + int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph().method())) : getIndex(name); STATIC_COUNTERS[index] += increment; GROUPS[index] = group; - ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph); - ConstantNode indexConstant = ConstantNode.forInt(index, graph); - LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); - IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph))); - StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); + ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph()); + ConstantNode indexConstant = ConstantNode.forInt(index, graph()); + LoadIndexedNode load = graph().add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); + IntegerAddNode add = graph().add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph()))); + StoreIndexedNode store = graph().add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); - graph.addBeforeFixed(this, load); - graph.addBeforeFixed(this, store); + graph().addBeforeFixed(this, load); + graph().addBeforeFixed(this, store); } - graph.removeFixed(this); + graph().removeFixed(this); } public static void addCounterBefore(String group, String name, long increment, boolean addContext, FixedNode position) { if (enabled) { - StructuredGraph graph = (StructuredGraph) position.graph(); + StructuredGraph graph = position.graph(); DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, group, increment, addContext)); graph.addBeforeFixed(position, counter); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Mon May 13 17:11:31 2013 +0200 @@ -44,9 +44,7 @@ public void simplify(SimplifierTool tool) { if (checkedValue instanceof FloatingNode && checkedValue.usages().count() == 1) { tool.addToWorkList(checkedValue); - ((StructuredGraph) graph()).removeFixed(this); - // ((StructuredGraph) graph()).replaceFixedWithFixed(this, graph().add(new - // DynamicCounterNode("non-surviving " + getName(), getIncrement(), isAddContext()))); + graph().removeFixed(this); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Mon May 13 17:11:31 2013 +0200 @@ -22,10 +22,9 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -public interface Access extends DeoptimizingNode { +public interface Access extends DeoptimizingNode, GuardedNode { ValueNode object(); @@ -33,5 +32,4 @@ void setNullCheck(boolean check); - Node asNode(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,10 +22,7 @@ */ package com.oracle.graal.nodes.extended; -import java.util.*; - import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -34,8 +31,9 @@ * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the * object. */ -public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access { +public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode { + @Input private GuardingNode guard; @Input private ValueNode object; @Input private ValueNode location; private boolean nullCheck; @@ -61,25 +59,18 @@ } public AccessNode(ValueNode object, ValueNode location, Stamp stamp) { + this(object, location, stamp, null); + } + + public AccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) { super(stamp); this.object = object; this.location = location; - } - - public AccessNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { - super(stamp, dependencies); - this.object = object; - this.location = location; - } - - public AccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - this.object = object; - this.location = location; + this.guard = guard; } @Override - public Node asNode() { + public AccessNode asNode() { return this; } @@ -92,4 +83,15 @@ public DeoptimizationReason getDeoptimizationReason() { return DeoptimizationReason.NullCheckException; } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * Location node that is the sum of two other location nodes. Can represent locations in the form of @@ -38,50 +39,69 @@ @Input private ValueNode x; @Input private ValueNode y; - public LocationNode getX() { + protected LocationNode getX() { return (LocationNode) x; } - public LocationNode getY() { + protected LocationNode getY() { return (LocationNode) y; } public static AddLocationNode create(LocationNode x, LocationNode y, Graph graph) { - assert x.getValueKind().equals(y.getValueKind()) && x.locationIdentity() == y.locationIdentity(); - return graph.unique(new AddLocationNode(x.locationIdentity(), x.getValueKind(), x, y)); + assert x.getValueKind().equals(y.getValueKind()) && x.getLocationIdentity() == y.getLocationIdentity(); + return graph.unique(new AddLocationNode(x, y)); } - private AddLocationNode(Object identity, Kind kind, ValueNode x, ValueNode y) { - super(identity, kind); + private AddLocationNode(ValueNode x, ValueNode y) { + super(StampFactory.extension()); this.x = x; this.y = y; } @Override - protected LocationNode addDisplacement(long displacement) { - LocationNode added = getX().addDisplacement(displacement); - return graph().unique(new AddLocationNode(locationIdentity(), getValueKind(), added, getY())); + public Kind getValueKind() { + return getX().getValueKind(); + } + + @Override + public LocationIdentity getLocationIdentity() { + return getX().getLocationIdentity(); } @Override public ValueNode canonical(CanonicalizerTool tool) { if (x instanceof ConstantLocationNode) { - return getY().addDisplacement(((ConstantLocationNode) x).displacement()); + return canonical((ConstantLocationNode) x, getY()); } if (y instanceof ConstantLocationNode) { - return getX().addDisplacement(((ConstantLocationNode) y).displacement()); + return canonical((ConstantLocationNode) y, getX()); } - if (x instanceof IndexedLocationNode && y instanceof IndexedLocationNode) { IndexedLocationNode xIdx = (IndexedLocationNode) x; IndexedLocationNode yIdx = (IndexedLocationNode) y; - if (xIdx.indexScaling() == yIdx.indexScaling()) { - long displacement = xIdx.displacement() + yIdx.displacement(); - ValueNode index = IntegerArithmeticNode.add(xIdx.index(), yIdx.index()); - return IndexedLocationNode.create(locationIdentity(), getValueKind(), displacement, index, graph(), xIdx.indexScaling()); + if (xIdx.getIndexScaling() == yIdx.getIndexScaling()) { + long displacement = xIdx.getDisplacement() + yIdx.getDisplacement(); + ValueNode index = IntegerArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex()); + return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, graph(), xIdx.getIndexScaling()); } } + return this; + } + private LocationNode canonical(ConstantLocationNode constant, LocationNode other) { + if (other instanceof ConstantLocationNode) { + ConstantLocationNode otherConst = (ConstantLocationNode) other; + return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), otherConst.getDisplacement() + constant.getDisplacement(), graph()); + } else if (other instanceof IndexedLocationNode) { + IndexedLocationNode otherIdx = (IndexedLocationNode) other; + return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), otherIdx.getDisplacement() + constant.getDisplacement(), otherIdx.getIndex(), graph(), otherIdx.getIndexScaling()); + } else if (other instanceof AddLocationNode) { + AddLocationNode otherAdd = (AddLocationNode) other; + LocationNode newInner = otherAdd.canonical(constant, otherAdd.getX()); + if (newInner != otherAdd) { + return AddLocationNode.create(newInner, otherAdd.getY(), graph()); + } + } return this; } @@ -92,5 +112,5 @@ } @NodeIntrinsic - public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y); + public static native Location addLocation(Location x, Location y); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon May 13 17:11:31 2013 +0200 @@ -76,7 +76,7 @@ VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); assert newVirtual.getFields().length == 1; - tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0); + tool.createVirtualObject(newVirtual, new ValueNode[]{v}, null); tool.replaceWithVirtual(newVirtual); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,36 +25,47 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * Location node that has a constant displacement. Can represent addresses of the form [base + disp] * where base is a node and disp is a constant. */ @NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}") -public class ConstantLocationNode extends LocationNode { +public final class ConstantLocationNode extends LocationNode { + private final Kind valueKind; + private final LocationIdentity locationIdentity; private final long displacement; - public long displacement() { - return displacement; - } - - public static ConstantLocationNode create(Object identity, Kind kind, long displacement, Graph graph) { + public static ConstantLocationNode create(LocationIdentity identity, Kind kind, long displacement, Graph graph) { return graph.unique(new ConstantLocationNode(identity, kind, displacement)); } - protected ConstantLocationNode(Object identity, Kind kind, long displacement) { - super(identity, kind); + private ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) { + super(StampFactory.extension()); + assert kind != Kind.Illegal && kind != Kind.Void; + this.valueKind = kind; + this.locationIdentity = identity; this.displacement = displacement; } @Override - protected ConstantLocationNode addDisplacement(long x) { - return create(locationIdentity(), getValueKind(), displacement + x, graph()); + public Kind getValueKind() { + return valueKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } + + public long getDisplacement() { + return displacement; } @Override public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitAddress(base, displacement(), Value.ILLEGAL, 0); + return gen.emitAddress(base, getDisplacement(), Value.ILLEGAL, 0); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.extended; -import java.util.*; - import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -36,12 +34,8 @@ super(object, location, stamp); } - public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { - super(object, location, stamp, dependencies); - } - - public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) { - super(object, location, stamp, dependencies); + public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) { + super(object, location, stamp, guard); } public abstract FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,15 +22,11 @@ */ package com.oracle.graal.nodes.extended; -import java.util.*; - import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; -public abstract class FloatingAccessNode extends FloatingNode implements Access { +public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access { @Input private ValueNode object; @Input private LocationNode location; @@ -63,20 +59,14 @@ this.location = location; } - public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, ValueNode... dependencies) { - super(stamp, dependencies); - this.object = object; - this.location = location; - } - - public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, List dependencies) { - super(stamp, dependencies); + public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard) { + super(stamp, guard); this.object = object; this.location = location; } @Override - public Node asNode() { + public FloatingAccessNode asNode() { return this; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.extended; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -38,13 +36,12 @@ @Input private Node lastLocationAccess; - public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, ValueNode... dependencies) { - super(object, location, stamp, dependencies); - this.lastLocationAccess = lastLocationAccess; + public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp) { + this(object, location, lastLocationAccess, stamp, null); } - public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, List dependencies) { - super(object, location, stamp, dependencies); + public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, GuardingNode guard) { + super(object, location, stamp, guard); this.lastLocationAccess = lastLocationAccess; } @@ -65,6 +62,6 @@ @Override public Access asFixedNode() { - return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), dependencies())); + return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard())); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardedNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,34 @@ +/* + * 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.nodes.*; + +public interface GuardedNode { + + GuardingNode getGuard(); + + void setGuard(GuardingNode guard); + + ValueNode asNode(); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GuardingNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,30 @@ +/* + * 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.nodes.*; + +public interface GuardingNode { + + ValueNode asNode(); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * Location node that has a displacement and a scaled index. Can represent locations in the form of @@ -35,65 +36,66 @@ @NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}") public final class IndexedLocationNode extends LocationNode implements Canonicalizable { + private final Kind valueKind; + private final LocationIdentity locationIdentity; + private final long displacement; @Input private ValueNode index; - private final long displacement; private final int indexScaling; /** * Gets the index or offset of this location. */ - public ValueNode index() { + public ValueNode getIndex() { return index; } - public long displacement() { + public long getDisplacement() { return displacement; } /** * @return Constant that is used to scale the index. */ - public int indexScaling() { + public int getIndexScaling() { return indexScaling; } - public static IndexedLocationNode create(Object identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) { + public static IndexedLocationNode create(LocationIdentity identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) { return graph.unique(new IndexedLocationNode(identity, kind, displacement, index, indexScaling)); } - private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int indexScaling) { - this(identity, kind, 0, index, indexScaling); - } - - private IndexedLocationNode(Object identity, Kind kind, long displacement, ValueNode index, int indexScaling) { - super(identity, kind); + private IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) { + super(StampFactory.extension()); + assert kind != Kind.Illegal && kind != Kind.Void; + this.valueKind = kind; + this.locationIdentity = identity; this.index = index; this.displacement = displacement; this.indexScaling = indexScaling; } @Override - protected LocationNode addDisplacement(long x) { - return create(locationIdentity(), getValueKind(), displacement + x, index, graph(), indexScaling); + public Kind getValueKind() { + return valueKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; } @Override public ValueNode canonical(CanonicalizerTool tool) { - Constant constantIndex = index.asConstant(); - if (constantIndex != null) { - long constantIndexLong = constantIndex.asLong(); - constantIndexLong *= indexScaling; - constantIndexLong += displacement; - return ConstantLocationNode.create(locationIdentity(), getValueKind(), constantIndexLong, graph()); + if (index == null || indexScaling == 0) { + return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), displacement, graph()); + } else if (index.isConstant()) { + return ConstantLocationNode.create(getLocationIdentity(), getValueKind(), index.asConstant().asLong() * indexScaling + displacement, graph()); } return this; } @Override public Value generateAddress(LIRGeneratorTool gen, Value base) { - return gen.emitAddress(base, displacement, gen.operand(index()), indexScaling()); + return gen.emitAddress(base, displacement, gen.operand(getIndex()), getIndexScaling()); } - - @NodeIntrinsic - public static native Location indexedLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, int index, @ConstantNodeParameter int indexScaling); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Mon May 13 17:11:31 2013 +0200 @@ -48,7 +48,7 @@ * @param keyProbabilities the probabilities of the keys * @param keySuccessors the successor index for each key */ - public IntegerSwitchNode(ValueNode value, BeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { + public IntegerSwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { super(value, successors, keySuccessors, keyProbabilities); assert keySuccessors.length == keys.length + 1; assert keySuccessors.length == keyProbabilities.length; @@ -66,7 +66,7 @@ * @param keySuccessors the successor index for each key */ public IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) { - this(value, new BeginNode[successorCount], keys, keyProbabilities, keySuccessors); + this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors); } /** @@ -94,7 +94,7 @@ public void simplify(SimplifierTool tool) { if (blockSuccessorCount() == 1) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); + graph().removeSplitPropagate(this, defaultSuccessor()); } else if (value() instanceof ConstantNode) { int constant = value().asConstant().asInt(); @@ -110,7 +110,7 @@ } } tool.addToWorkList(blockSuccessor(survivingEdge)); - ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge)); + graph().removeSplit(this, blockSuccessor(survivingEdge)); } else if (value() != null) { IntegerStamp stamp = value().integerStamp(); if (!stamp.isUnrestricted()) { @@ -122,9 +122,9 @@ } if (validKeys == 0) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); + graph().removeSplitPropagate(this, defaultSuccessor()); } else if (validKeys != keys.length) { - ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); + ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); int[] newKeys = new int[validKeys]; int[] newKeySuccessors = new int[validKeys + 1]; double[] newKeyProbabilities = new double[validKeys + 1]; @@ -153,14 +153,14 @@ } for (int i = 0; i < blockSuccessorCount(); i++) { - BeginNode successor = blockSuccessor(i); + AbstractBeginNode successor = blockSuccessor(i); if (!newSuccessors.contains(successor)) { tool.deleteBranch(successor); } setBlockSuccessor(i, null); } - BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]); + AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]); IntegerSwitchNode newSwitch = graph().add(new IntegerSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors)); ((FixedWithNextNode) predecessor()).setNext(newSwitch); GraphUtil.killWithUnusedFloatingInputs(this); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Loads a method from the virtual method table of a given hub. + */ +public final class LoadMethodNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode hub; + private final ResolvedJavaMethod method; + + public ValueNode getHub() { + return hub; + } + + public LoadMethodNode(ResolvedJavaMethod method, ValueNode hub, Kind kind) { + super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind)); + this.hub = hub; + this.method = method; + assert !Modifier.isAbstract(method.getModifiers()) : "Cannot load abstract method from a hub"; + assert !Modifier.isStatic(method.getModifiers()) : "Cannot load a static method from a hub"; + assert method.isInVirtualMethodTable(); + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + tool.getRuntime().lower(this, tool); + } + + public ResolvedJavaMethod getMethod() { + return method; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ValueNumberable; import com.oracle.graal.nodes.calc.*; @@ -35,8 +37,25 @@ */ public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable { - private Kind valueKind; - private Object locationIdentity; + /** + * Marker interface for location identities. Apart from the special values {@link #ANY_LOCATION} + * and {@link #FINAL_LOCATION}, a different location identity of two memory accesses guarantees + * that the two accesses do not interfere. + */ + public interface LocationIdentity { + } + + /** + * Denotes any location. A write to such a location kills all values in a memory map during an + * analysis of memory accesses in a graph. A read from this location cannot be moved or + * coalesced with other reads because its interaction with other reads is not known. + */ + public static final LocationIdentity ANY_LOCATION = createLocation("ANY_LOCATION"); + + /** + * Denotes the location of a value that is guaranteed to be final. + */ + public static final LocationIdentity FINAL_LOCATION = createLocation("FINAL_LOCATION"); /** * Creates a new unique location identity for read and write operations. @@ -44,8 +63,8 @@ * @param name the name of the new location identity, for debugging purposes * @return the new location identity */ - public static Object createLocation(final String name) { - return new Object() { + public static LocationIdentity createLocation(final String name) { + return new LocationIdentity() { @Override public String toString() { @@ -55,16 +74,23 @@ } /** - * Denotes any location. A write to such a location kills all values in a memory map during an - * analysis of memory accesses in a graph. A read from this location cannot be moved or - * coalesced with other reads because its interaction with other reads is not known. + * Returns the location identity for an array of the given element kind. Array accesses of the + * same kind must have the same location identity unless an alias analysis guarantees that two + * distinct arrays are accessed. */ - public static final Object ANY_LOCATION = createLocation("ANY_LOCATION"); + public static LocationIdentity getArrayLocation(Kind elementKind) { + return ARRAY_LOCATIONS.get(elementKind); + } + + private static final EnumMap ARRAY_LOCATIONS = initArrayLocations(); - /** - * Denotes the location of a value that is guaranteed to be final. - */ - public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION"); + private static EnumMap initArrayLocations() { + EnumMap result = new EnumMap<>(Kind.class); + for (Kind kind : Kind.values()) { + result.put(kind, createLocation("Array: " + kind.getJavaName())); + } + return result; + } /** * Marker interface for locations in snippets. @@ -72,29 +98,22 @@ public interface Location { } - public static Object getArrayLocation(Kind elementKind) { - return elementKind; - } - - protected LocationNode(Object identity, Kind kind) { - super(StampFactory.extension()); - assert kind != Kind.Illegal && kind != Kind.Void; - this.valueKind = kind; - this.locationIdentity = identity; + protected LocationNode(Stamp stamp) { + super(stamp); } - public Kind getValueKind() { - return valueKind; - } + /** + * Returns the kind of the accessed memory value. + */ + public abstract Kind getValueKind(); - public Object locationIdentity() { - return locationIdentity; - } - - protected abstract LocationNode addDisplacement(long displacement); + /** + * Returns the identity of the accessed memory location. + */ + public abstract LocationIdentity getLocationIdentity(); @Override - public void generate(LIRGeneratorTool generator) { + public final void generate(LIRGeneratorTool generator) { // nothing to do... } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Mon May 13 17:11:31 2013 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -50,8 +51,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Mon May 13 17:11:31 2013 +0200 @@ -23,11 +23,12 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; /** - * This interface marks is used for 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). + * 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 { @@ -37,6 +38,6 @@ * * @return the identities of all locations killed by this node. */ - Object[] getLocationIdentities(); + LocationIdentity[] getLocationIdentities(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable { +public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode { @Input public ValueNode object; @@ -54,4 +54,9 @@ public DeoptimizationReason getDeoptimizationReason() { return DeoptimizationReason.NullCheckException; } + + @Override + public ValueNode asNode() { + return this; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +@NodeInfo(nameTemplate = "OSRLocal({p#index})") +public class OSRLocalNode extends AbstractLocalNode implements Node.IterableNodeType { + + public OSRLocalNode(int index, Stamp stamp) { + super(index, stamp); + } + +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +public class OSRStartNode extends StartNode implements Lowerable { + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } + } + + public NodeIterable getOSRLocals() { + return usages().filter(OSRLocalNode.class); + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,11 +22,10 @@ */ package com.oracle.graal.nodes.extended; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -39,20 +38,20 @@ super(object, location, stamp); } - public ReadNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { - super(object, location, stamp, dependencies); + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard) { + super(object, location, stamp, guard); } - private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) { + private ReadNode(ValueNode object, int displacement, LocationIdentity locationIdentity, Kind kind) { super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind)); } - private ReadNode(ValueNode object, ValueNode location, ValueNode dependency) { + private ReadNode(ValueNode object, ValueNode location, GuardingNode guard) { /* * Used by node intrinsics. Since the initial value for location is a parameter, i.e., a * LocalNode, the constructor cannot use the declared type LocationNode. */ - super(object, location, StampFactory.forNodeIntrinsic(), dependency); + super(object, location, StampFactory.forNodeIntrinsic(), guard); } @Override @@ -68,14 +67,14 @@ @Override public FloatingAccessNode asFloatingNode(ValueNode lastLocationAccess) { - return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), dependencies())); + return graph().unique(new FloatingReadNode(object(), location(), lastLocationAccess, stamp(), getGuard())); } public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) { MetaAccessProvider runtime = tool.runtime(); if (runtime != null && object != null && object.isConstant()) { - if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) { - long displacement = ((ConstantLocationNode) location).displacement(); + if (location.getLocationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) { + long displacement = ((ConstantLocationNode) location).getDisplacement(); Kind kind = location.getValueKind(); if (object.kind() == Kind.Object) { Object base = object.asConstant().asObject(); @@ -101,19 +100,27 @@ @Override public boolean push(PiNode parent) { - Object locId = location().locationIdentity(); - if (locId instanceof ResolvedJavaField) { - ResolvedJavaType fieldType = ((ResolvedJavaField) locId).getDeclaringClass(); - ValueNode piValueStamp = parent.object(); - ResolvedJavaType beforePiType = piValueStamp.objectStamp().type(); + if (location() instanceof ConstantLocationNode) { + long displacement = ((ConstantLocationNode) location()).getDisplacement(); + if (parent.stamp() instanceof ObjectStamp) { + ObjectStamp piStamp = parent.objectStamp(); + ResolvedJavaType receiverType = piStamp.type(); + if (receiverType != null) { + ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(displacement); - if (beforePiType != null && fieldType.isAssignableFrom(beforePiType)) { - ObjectStamp piStamp = parent.objectStamp(); - if (piStamp.nonNull() == piValueStamp.objectStamp().nonNull() && piStamp.alwaysNull() == piValueStamp.objectStamp().alwaysNull()) { - replaceFirstInput(parent, piValueStamp); - return true; + if (field != null) { + ResolvedJavaType declaringClass = field.getDeclaringClass(); + if (declaringClass.isAssignableFrom(receiverType) && declaringClass != receiverType) { + ObjectStamp piValueStamp = parent.object().objectStamp(); + if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) { + replaceFirstInput(parent, parent.object()); + return true; + } + } + } } } + } return false; } @@ -128,5 +135,5 @@ * @return the value read from memory */ @NodeIntrinsic(setStampFromReturnType = true) - public static native T read(Object base, @ConstantNodeParameter int displacement, @ConstantNodeParameter Object locationIdentity, @ConstantNodeParameter Kind kind); + public static native T read(Object base, @ConstantNodeParameter int displacement, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter Kind kind); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Mon May 13 17:11:31 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -50,8 +51,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SnippetLocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Location node that can be used inside a snippet without having the elements (including the + * location identity and kind) as a snippet constant. Can represent locations in the form of [base + + * index * scale + disp]. When the location is created, all elements (base, index, scale, disp) are + * nodes. Both scale and disp must eventually canonicalize to {@link ConstantNode constants} so that + * this node can be canonicalized to a {@link IndexedLocationNode} or {@link ConstantLocationNode}. + */ +public final class SnippetLocationNode extends LocationNode implements Canonicalizable { + + @Input private ValueNode valueKind; + @Input private ValueNode locationIdentity; + @Input private ValueNode displacement; + @Input private ValueNode index; + @Input private ValueNode indexScaling; + + public static SnippetLocationNode create(ValueNode identity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling, Graph graph) { + return graph.unique(new SnippetLocationNode(identity, kind, displacement, index, indexScaling)); + } + + private SnippetLocationNode(ValueNode locationIdentity, ValueNode kind, ValueNode displacement) { + this(locationIdentity, kind, displacement, null, null); + } + + private SnippetLocationNode(ValueNode locationIdentity, ValueNode kind, ValueNode displacement, ValueNode index, ValueNode indexScaling) { + super(StampFactory.object()); + this.valueKind = kind; + this.locationIdentity = locationIdentity; + this.displacement = displacement; + this.index = index; + this.indexScaling = indexScaling; + } + + @Override + public Kind getValueKind() { + if (valueKind.isConstant()) { + return (Kind) valueKind.asConstant().asObject(); + } + throw new GraalInternalError("Cannot access kind yet because it is not constant: " + valueKind); + } + + @Override + public LocationIdentity getLocationIdentity() { + if (locationIdentity.isConstant()) { + return (LocationIdentity) locationIdentity.asConstant().asObject(); + } + // We do not know our actual location identity yet, so be conservative. + return LocationNode.ANY_LOCATION; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (valueKind.isConstant() && locationIdentity.isConstant() && displacement.isConstant() && (indexScaling == null || indexScaling.isConstant())) { + Kind constKind = (Kind) valueKind.asConstant().asObject(); + LocationIdentity constLocation = (LocationIdentity) locationIdentity.asConstant().asObject(); + long constDisplacement = displacement.asConstant().asLong(); + int constIndexScaling = indexScaling == null ? 0 : indexScaling.asConstant().asInt(); + + if (index == null || constIndexScaling == 0) { + return ConstantLocationNode.create(constLocation, constKind, constDisplacement, graph()); + } else if (index.isConstant()) { + return ConstantLocationNode.create(constLocation, constKind, index.asConstant().asLong() * constIndexScaling + constDisplacement, graph()); + } else { + return IndexedLocationNode.create(constLocation, constKind, constDisplacement, index, graph(), constIndexScaling); + } + } + return this; + } + + @Override + public Value generateAddress(LIRGeneratorTool gen, Value base) { + throw new GraalInternalError("locationIdentity must be a constant so that this node can be canonicalized: " + locationIdentity); + } + + @NodeIntrinsic + public static native Location constantLocation(LocationIdentity identity, Kind kind, long displacement); + + @NodeIntrinsic + public static native Location indexedLocation(LocationIdentity identity, Kind kind, long displacement, int index, int indexScaling); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Mon May 13 17:11:31 2013 +0200 @@ -34,7 +34,7 @@ */ public abstract class SwitchNode extends ControlSplitNode { - @Successor protected final NodeSuccessorList successors; + @Successor protected final NodeSuccessorList successors; @Input private ValueNode value; private double[] keyProbabilities; private int[] keySuccessors; @@ -45,17 +45,25 @@ * @param value the instruction that provides the value to be switched over * @param successors the list of successors of this switch */ - public SwitchNode(ValueNode value, BeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) { + public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) { super(StampFactory.forVoid()); assert keySuccessors.length == keyProbabilities.length; this.successors = new NodeSuccessorList<>(this, successors); this.value = value; this.keySuccessors = keySuccessors; this.keyProbabilities = keyProbabilities; + assert assertProbabilities(); + } + + private boolean assertProbabilities() { + for (double d : keyProbabilities) { + assert d >= 0.0 : "Cannot have negative probabilities in switch node: " + d; + } + return true; } @Override - public double probability(BeginNode successor) { + public double probability(AbstractBeginNode successor) { double sum = 0; for (int i = 0; i < keySuccessors.length; i++) { if (successors.get(keySuccessors[i]) == successor) { @@ -89,7 +97,7 @@ /** * Returns the successor for the key at the given index. */ - public BeginNode keySuccessor(int i) { + public AbstractBeginNode keySuccessor(int i) { return successors.get(keySuccessors[i]); } @@ -107,11 +115,11 @@ return keySuccessors[keySuccessors.length - 1]; } - public BeginNode blockSuccessor(int i) { + public AbstractBeginNode blockSuccessor(int i) { return successors.get(i); } - public void setBlockSuccessor(int i, BeginNode s) { + public void setBlockSuccessor(int i, AbstractBeginNode s) { successors.set(i, s); } @@ -124,7 +132,7 @@ * * @return the default successor */ - public BeginNode defaultSuccessor() { + public AbstractBeginNode defaultSuccessor() { if (defaultSuccessorIndex() == -1) { throw new GraalInternalError("unexpected"); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon May 13 17:11:31 2013 +0200 @@ -79,9 +79,9 @@ case Long: return ConstantNode.forLong((Long) o, graph()); case Float: - return ConstantNode.forFloat((Long) o, graph()); + return ConstantNode.forFloat((Float) o, graph()); case Double: - return ConstantNode.forDouble((Long) o, graph()); + return ConstantNode.forDouble((Double) o, graph()); default: ValueNodeUtil.shouldNotReachHere(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java Mon May 13 17:11:31 2013 +0200 @@ -37,6 +37,11 @@ return length; } + public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp) { + super(object, stamp); + this.length = length; + } + public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, ValueNode anchor) { super(object, stamp, anchor); this.length = length; @@ -51,5 +56,8 @@ } @NodeIntrinsic + public static native T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp); + + @NodeIntrinsic public static native T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp, Object anchor); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Mon May 13 17:11:31 2013 +0200 @@ -37,7 +37,7 @@ } public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) { - super(object, stamp, anchor); + super(object, stamp, (FixedNode) anchor); } public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) { @@ -90,7 +90,7 @@ @Override public void generate(LIRGeneratorTool generator) { if (kind() != object().kind()) { - assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value"; + assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value"; AllocatableValue result = generator.newVariable(kind()); generator.emitMove(result, generator.operand(object())); generator.setResult(this, result); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -74,8 +75,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Mon May 13 17:11:31 2013 +0200 @@ -34,15 +34,18 @@ /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. */ -public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable { +public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable, GuardingNode { + + @Input private NodeInputList anchored; public ValueAnchorNode(ValueNode... values) { this(false, values); } public ValueAnchorNode(boolean permanent, ValueNode... values) { - super(StampFactory.dependency(), values); + super(StampFactory.dependency()); this.permanent = permanent; + this.anchored = new NodeInputList<>(this, values); } private final boolean permanent; @@ -53,8 +56,8 @@ } public void addAnchoredNode(ValueNode value) { - if (!this.dependencies().contains(value)) { - this.dependencies().add(value); + if (!anchored.contains(value)) { + this.anchored.add(value); } } @@ -67,13 +70,13 @@ ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor(); if (previousAnchor.usages().isEmpty()) { // avoid creating cycles // transfer values and remove - for (ValueNode node : dependencies().nonNull().distinct()) { + for (ValueNode node : anchored.nonNull().distinct()) { previousAnchor.addAnchoredNode(node); } return previousAnchor; } } - for (Node node : dependencies().nonNull().and(isNotA(FixedNode.class))) { + for (Node node : anchored.nonNull().and(isNotA(FixedNode.class))) { if (node instanceof ConstantNode) { continue; } @@ -100,7 +103,7 @@ if (permanent) { return; } - for (ValueNode node : dependencies().nonNull().and(isNotA(BeginNode.class))) { + for (ValueNode node : anchored.nonNull().and(isNotA(AbstractBeginNode.class))) { State state = tool.getObjectState(node); if (state == null || state.getState() != EscapeState.Virtual) { return; @@ -108,4 +111,9 @@ } tool.delete(); } + + @Override + public ValueNode asNode() { + return this; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Mon May 13 17:11:31 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -37,8 +38,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,6 +25,8 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.LocationNode.Location; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -90,10 +92,10 @@ } @NodeIntrinsic - public static native void writeMemory(Object object, Object value, Object location, @ConstantNodeParameter boolean usePreciseWriteBarriers); + public static native void writeMemory(Object object, Object value, Location location, @ConstantNodeParameter WriteBarrierType barrierType); @Override - public Object[] getLocationIdentities() { - return new Object[]{location().locationIdentity()}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{location().getLocationIdentity()}; } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Mon May 13 17:11:31 2013 +0200 @@ -34,7 +34,7 @@ public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable { @Input private ValueNode index; - private final Kind elementType; + private final Kind elementKind; public ValueNode index() { return index; @@ -46,12 +46,12 @@ * @param stamp the result kind of the access * @param array the instruction producing the array * @param index the instruction producing the index - * @param elementKind the type of the elements of the array + * @param elementKind the kind of the elements of the array */ protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) { super(stamp, array); this.index = index; - this.elementType = elementKind; + this.elementKind = elementKind; } /** @@ -60,7 +60,7 @@ * @return the element type */ public Kind elementKind() { - return elementType; + return elementKind; } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Mon May 13 17:11:31 2013 +0200 @@ -23,43 +23,24 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.code.*; -import com.oracle.graal.debug.*; 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.virtual.*; /** * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release. *

    - * The VM needs information about monitors in the debug information. This information is built from - * the nesting level of {@link MonitorEnterNode} when the LIR is constructed. Therefore, monitor - * nodes must not be removed from the graph unless it is guaranteed that the nesting level does not - * change. For example, you must not remove a {@link MonitorEnterNode} for a thread-local object or - * for a recursive locking. Instead, mark the node as {@link #eliminated}. This makes sure that the - * meta data still contains the complete locking hierarchy. - *

    * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and * throws a {@link BailoutException} instead during graph building. */ -public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint, Virtualizable { +public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint { @Input private ValueNode object; - private boolean eliminated; public ValueNode object() { return object; } - public boolean eliminated() { - return eliminated; - } - - public void eliminate() { - eliminated = true; - } - /** * Creates a new AccessMonitor instruction. * @@ -69,22 +50,4 @@ super(StampFactory.forVoid()); this.object = object; } - - @Override - public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().getClass() == VirtualInstanceNode.class) { - Debug.log("monitor operation %s on %s\n", this, state); - int newLockCount = state.getLockCount() + (this instanceof MonitorEnterNode ? 1 : -1); - state.setLockCount(newLockCount); - tool.replaceFirstInput(object(), state.getVirtualObject()); - tool.customAction(new Runnable() { - - @Override - public void run() { - eliminate(); - } - }); - } - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.java; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -37,13 +38,24 @@ @Input private ValueNode type; /** + * Determines the exception thrown by this node if the check fails: {@link ClassCastException} + * if false; {@link ArrayStoreException} if true. + */ + private final boolean forStoreCheck; + + /** * @param type the type being cast to * @param object the instruction producing the object */ - public CheckCastDynamicNode(ValueNode type, ValueNode object) { + public CheckCastDynamicNode(ValueNode type, ValueNode object, boolean forStoreCheck) { super(object.stamp()); this.type = type; this.object = object; + this.forStoreCheck = forStoreCheck; + } + + public boolean isForStoreCheck() { + return forStoreCheck; } @Override @@ -67,6 +79,11 @@ if (object().objectStamp().alwaysNull()) { return object(); } + if (type().isConstant() && type().kind() == Kind.Object && type().asConstant().asObject() instanceof Class) { + Class clazz = (Class) type().asConstant().asObject(); + ResolvedJavaType t = tool.runtime().lookupJavaType(clazz); + return graph().add(new CheckCastNode(t, object(), null, forStoreCheck)); + } return this; } @@ -80,4 +97,7 @@ public ValueNode type() { return type; } + + @NodeIntrinsic + public static native T checkCastDynamic(Class type, Object object, @ConstantNodeParameter boolean forStoreCheck); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon May 13 17:11:31 2013 +0200 @@ -38,17 +38,28 @@ private final JavaTypeProfile profile; /** + * Determines the exception thrown by this node if the check fails: {@link ClassCastException} + * if false; {@link ArrayStoreException} if true. + */ + private final boolean forStoreCheck; + + /** * Creates a new CheckCast instruction. * * @param type the type being cast to * @param object the instruction producing the object */ - public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { + public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) { super(StampFactory.declared(type)); assert type != null; this.type = type; this.object = object; this.profile = profile; + this.forStoreCheck = forStoreCheck; + } + + public boolean isForStoreCheck() { + return forStoreCheck; } @Override @@ -68,26 +79,35 @@ public ValueNode canonical(CanonicalizerTool tool) { assert object() != null : this; - if (type != null) { - ResolvedJavaType objectType = object().objectStamp().type(); - if (objectType != null && type.isAssignableFrom(objectType)) { - // we don't have to check for null types here because they will also pass the - // checkcast. - return object(); - } + ResolvedJavaType objectType = object().objectStamp().type(); + if (objectType != null && type.isAssignableFrom(objectType)) { + // we don't have to check for null types here because they will also pass the + // checkcast. + return object(); + } - // remove checkcast if the only usage is a more specific checkcast - if (usages().count() == 1) { - CheckCastNode ccn = usages().filter(CheckCastNode.class).first(); - if (ccn != null && ccn.type() != null && type.isAssignableFrom(ccn.type())) { - return object(); - } + // remove checkcast if next node is a more specific checkcast + if (predecessor() instanceof CheckCastNode) { + CheckCastNode ccn = (CheckCastNode) predecessor(); + if (ccn != null && ccn.type != null && ccn == object && ccn.forStoreCheck == forStoreCheck && ccn.type.isAssignableFrom(type)) { + StructuredGraph graph = ccn.graph(); + CheckCastNode newccn = graph.add(new CheckCastNode(type, ccn.object, ccn.profile, ccn.forStoreCheck)); + graph.replaceFixedWithFixed(ccn, newccn); + return newccn; } } if (object().objectStamp().alwaysNull()) { return object(); } + if (tool.assumptions().useOptimisticAssumptions()) { + ResolvedJavaType exactType = type.findUniqueConcreteSubtype(); + if (exactType != null && exactType != type) { + // Propagate more precise type information to usages of the checkcast. + tool.assumptions().recordConcreteSubtype(type, exactType); + return graph().add(new CheckCastNode(exactType, object, profile, forStoreCheck)); + } + } return this; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Mon May 13 17:11:31 2013 +0200 @@ -28,7 +28,8 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.extended.WriteNode.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; +import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -95,8 +96,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Mon May 13 17:11:31 2013 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -39,8 +40,8 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } @Override @@ -57,11 +58,10 @@ if (isLowered()) { return; } - StructuredGraph graph = (StructuredGraph) graph(); - LoadExceptionObjectNode loadException = graph.add(new LoadExceptionObjectNode(stamp())); + LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp())); loadException.setStateAfter(stateAfter()); replaceAtUsages(loadException); - graph.addAfterFixed(this, loadException); + graph().addAfterFixed(this, loadException); tool.setLastFixedNode(loadException); setStateAfter(null); setStamp(StampFactory.forVoid()); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Mon May 13 17:11:31 2013 +0200 @@ -80,7 +80,7 @@ @Override public boolean verify() { for (Node usage : usages()) { - assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage); + assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage); } return super.verify(); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Mon May 13 17:11:31 2013 +0200 @@ -36,7 +36,7 @@ @Input private ValueNode object; private final ResolvedJavaType type; - private final JavaTypeProfile profile; + private JavaTypeProfile profile; /** * Constructs a new InstanceOfNode. @@ -109,10 +109,14 @@ return profile; } + public void setProfile(JavaTypeProfile profile) { + this.profile = profile; + } + @Override public boolean verify() { for (Node usage : usages()) { - assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); + assertTrue(usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); } return super.verify(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Mon May 13 17:11:31 2013 +0200 @@ -53,6 +53,11 @@ } @Override + public boolean inferStamp() { + return updateStamp(createStamp(array(), elementKind())); + } + + @Override public void virtualize(VirtualizerTool tool) { State arrayState = tool.getObjectState(array()); if (arrayState != null && arrayState.getState() == EscapeState.Virtual) { diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Mon May 13 17:11:31 2013 +0200 @@ -24,12 +24,13 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. */ -public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference { +public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MonitorReference { private int lockDepth; @@ -44,10 +45,11 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } + @Override public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } @@ -59,4 +61,13 @@ public void setLockDepth(int lockDepth) { this.lockDepth = lockDepth; } + + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(object()); + if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { + state.addLock(getLockDepth()); + tool.delete(); + } + } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,15 +22,16 @@ */ package com.oracle.graal.nodes.java; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.graph.*; /** * The {@code MonitorEnterNode} represents a monitor release. */ -public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference { +public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference { private int lockDepth; @@ -45,10 +46,11 @@ } @Override - public Object[] getLocationIdentities() { - return new Object[]{LocationNode.ANY_LOCATION}; + public LocationIdentity[] getLocationIdentities() { + return new LocationIdentity[]{LocationNode.ANY_LOCATION}; } + @Override public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } @@ -60,4 +62,14 @@ public void setLockDepth(int lockDepth) { this.lockDepth = lockDepth; } + + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(object()); + if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { + int removedLock = state.removeLock(); + assert removedLock == getLockDepth(); + tool.delete(); + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Mon May 13 17:11:31 2013 +0200 @@ -38,8 +38,6 @@ private final ResolvedJavaType elementType; private final boolean fillContents; - private final boolean locked; - @Override public ValueNode length() { return length; @@ -52,14 +50,12 @@ * the array itself). * @param length the node that produces the length for this allocation. * @param fillContents determines whether the array elements should be initialized to zero/null. - * @param locked determines whether the array should be locked immediately. */ - public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents, boolean locked) { + public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) { super(StampFactory.exactNonNull(elementType.getArrayClass())); this.length = length; this.elementType = elementType; this.fillContents = fillContents; - this.locked = locked; } /** @@ -70,13 +66,6 @@ } /** - * @return true if the array will be locked immediately. - */ - public boolean locked() { - return locked; - } - - /** * The list of node which produce input for this instruction. */ public ValueNode dimension(int index) { @@ -111,7 +100,9 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - tool.getRuntime().lower(this, tool); + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } } @Override @@ -125,7 +116,7 @@ state[i] = defaultForKind; } VirtualObjectNode virtualObject = new VirtualArrayNode(elementType, constantLength); - tool.createVirtualObject(virtualObject, state, 0); + tool.createVirtualObject(virtualObject, state, null); tool.replaceWithVirtual(virtualObject); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Mon May 13 17:11:31 2013 +0200 @@ -37,7 +37,6 @@ private final ResolvedJavaType instanceClass; private final boolean fillContents; - private final boolean locked; /** * Constructs a NewInstanceNode. @@ -45,13 +44,11 @@ * @param type the class being allocated * @param fillContents determines whether the new object's fields should be initialized to * zero/null. - * @param locked determines whether the new object should be locked immediately. */ - public NewInstanceNode(ResolvedJavaType type, boolean fillContents, boolean locked) { + public NewInstanceNode(ResolvedJavaType type, boolean fillContents) { super(StampFactory.exactNonNull(type)); this.instanceClass = type; this.fillContents = fillContents; - this.locked = locked; } /** @@ -70,13 +67,6 @@ return fillContents; } - /** - * @return true if the new object will be locked immediately. - */ - public boolean locked() { - return locked; - } - @Override public ValueNode canonical(CanonicalizerTool tool) { if (usages().isEmpty()) { @@ -88,7 +78,9 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - tool.getRuntime().lower(this, tool); + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } } @Override @@ -101,7 +93,7 @@ for (int i = 0; i < state.length; i++) { state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph()); } - tool.createVirtualObject(virtualObject, state, 0); + tool.createVirtualObject(virtualObject, state, null); tool.replaceWithVirtual(virtualObject); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Mon May 13 17:11:31 2013 +0200 @@ -63,7 +63,9 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - tool.getRuntime().lower(this, tool); + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } } public ResolvedJavaType type() { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Mon May 13 17:11:31 2013 +0200 @@ -73,8 +73,11 @@ ValueNode indexValue = tool.getReplacedValue(index()); int index = indexValue.isConstant() ? indexValue.asConstant().asInt() : -1; if (index >= 0 && index < arrayState.getVirtualObject().entryCount()) { - tool.setVirtualEntry(arrayState, index, value()); - tool.delete(); + ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType(); + if (componentType.isPrimitive() || value.objectStamp().alwaysNull() || componentType.isAssignableFrom(value.objectStamp().type())) { + tool.setVirtualEntry(arrayState, index, value()); + tool.delete(); + } } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Mon May 13 17:11:31 2013 +0200 @@ -50,7 +50,7 @@ * @param keyProbabilities the probabilities of the keys * @param keySuccessors the successor index for each key */ - public TypeSwitchNode(ValueNode value, BeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) { + public TypeSwitchNode(ValueNode value, AbstractBeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) { super(value, successors, keySuccessors, keyProbabilities); assert successors.length <= keys.length + 1; assert keySuccessors.length == keyProbabilities.length; @@ -95,7 +95,7 @@ } } tool.addToWorkList(blockSuccessor(survivingEdge)); - ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge)); + graph().removeSplit(this, blockSuccessor(survivingEdge)); } if (value() instanceof LoadHubNode) { ObjectStamp stamp = ((LoadHubNode) value()).object().objectStamp(); @@ -108,9 +108,9 @@ } if (validKeys == 0) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); + graph().removeSplitPropagate(this, defaultSuccessor()); } else if (validKeys != keys.length) { - ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); + ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys]; int[] newKeySuccessors = new int[validKeys + 1]; double[] newKeyProbabilities = new double[validKeys + 1]; @@ -139,14 +139,14 @@ } for (int i = 0; i < blockSuccessorCount(); i++) { - BeginNode successor = blockSuccessor(i); + AbstractBeginNode successor = blockSuccessor(i); if (!newSuccessors.contains(successor)) { tool.deleteBranch(successor); } setBlockSuccessor(i, null); } - BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]); + AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]); TypeSwitchNode newSwitch = graph().add(new TypeSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors)); ((FixedWithNextNode) predecessor()).setNext(newSwitch); GraphUtil.killWithUnusedFloatingInputs(this); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Mon May 13 17:11:31 2013 +0200 @@ -49,7 +49,7 @@ Value operand(ValueNode object); - AllocatableValue newVariable(Kind kind); + AllocatableValue newVariable(PlatformKind kind); Value setResult(ValueNode x, Value operand); @@ -116,7 +116,7 @@ // Handling of block-end nodes still needs to be unified in the LIRGenerator. void visitMerge(MergeNode i); - void visitEndNode(EndNode i); + void visitEndNode(AbstractEndNode i); void visitLoopEnd(LoopEndNode i); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; public interface LoweringTool { @@ -34,11 +35,11 @@ Replacements getReplacements(); - ValueNode createNullCheckGuard(ValueNode object); + GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object); - ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); + GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); - ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated); + GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated); Assumptions assumptions(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java Mon May 13 17:11:31 2013 +0200 @@ -28,15 +28,15 @@ * This interface marks a node as being able to negate its effect, this is intended for nodes that * depend on a BooleanNode condition. The canonical representation of has, for example, no way to * represent a != b. If such an expression appears during canonicalization the negated expression - * will be created (a == b) and the usages will be negated, using this interface's {@link #negate()} - * method. + * will be created (a == b) and the usages will be negated, using this interface's + * {@link #negate(LogicNode)} method. */ public interface Negatable { /** * Tells this node that a condition it depends has been negated, and that it thus needs to - * invert its own effect. For example, an {@link IfNode} would switch its true and false - * successors. + * invert the effects of this condition. For example, an {@link IfNode} would switch its true + * and false successors. */ - Negatable negate(); + Negatable negate(LogicNode condition); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Mon May 13 17:11:31 2013 +0200 @@ -47,9 +47,9 @@ public abstract ValueNode getEntry(int index); - public abstract int getLockCount(); + public abstract void addLock(int depth); - public abstract void setLockCount(int lockCount); + public abstract int removeLock(); public abstract ValueNode getMaterializedValue(); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Mon May 13 17:11:31 2013 +0200 @@ -64,9 +64,9 @@ * * @param virtualObject the new virtual object. * @param entryState the initial state of the virtual object's fields. - * @param lockCount the initial locking depth. + * @param locks the initial locking depths. */ - void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount); + void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks); /** * Queries the current state of the given value: if it is virtualized (thread-local and the @@ -138,12 +138,12 @@ void replaceFirstInput(Node oldInput, Node replacement); /** - * Performs a custom action on the current node. This action will only be performed when, and - * if, the changes are committed. Custom actions must not modify inputs of nodes. + * Adds the given node to the graph.This action will only be performed when, and if, the changes + * are committed. * - * @param action the custom action. + * @param node the node to add. */ - void customAction(Runnable action); + void addNode(ValueNode node); /** * This method performs either {@link #replaceWithValue(ValueNode)} or diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java Mon May 13 17:11:31 2013 +0200 @@ -147,7 +147,7 @@ private void processMerge(MergeNode merge, DominatorInfo info) { // TTY.println("processMerge(" + merge + ", " + info + ")"); - for (EndNode end : merge.cfgPredecessors()) { + for (AbstractEndNode end : merge.cfgPredecessors()) { toExplore.add(end); infoMap.set(end, info.createChild(end)); // TTY.println(" Enqueue end : " + end + " with " + infoMap.get(end)); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon May 13 17:11:31 2013 +0200 @@ -44,9 +44,9 @@ public static void killCFG(FixedNode node) { assert node.isAlive(); - if (node instanceof EndNode) { + if (node instanceof AbstractEndNode) { // We reached a control flow end. - EndNode end = (EndNode) node; + AbstractEndNode end = (AbstractEndNode) node; killEnd(end); } else { // Normal control flow node. @@ -63,11 +63,11 @@ propagateKill(node); } - private static void killEnd(EndNode end) { + private static void killEnd(AbstractEndNode end) { MergeNode merge = end.merge(); if (merge != null) { merge.removeEnd(end); - StructuredGraph graph = (StructuredGraph) end.graph(); + StructuredGraph graph = end.graph(); if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop for (PhiNode phi : merge.phis().snapshot()) { propagateKill(phi); @@ -141,7 +141,7 @@ if (singleValue != null) { Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); Collection proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot(); - ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); + phiNode.graph().replaceFloating(phiNode, singleValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } @@ -152,7 +152,7 @@ } public static void checkRedundantProxy(ProxyNode vpn) { - BeginNode proxyPoint = vpn.proxyPoint(); + AbstractBeginNode proxyPoint = vpn.proxyPoint(); if (proxyPoint instanceof LoopExitNode) { LoopExitNode exit = (LoopExitNode) proxyPoint; LoopBeginNode loopBegin = exit.loopBegin(); @@ -165,7 +165,7 @@ if (vpnValue == v2) { Collection phiUsages = vpn.usages().filter(PhiNode.class).snapshot(); Collection proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot(); - ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue); + vpn.graph().replaceFloating(vpn, vpnValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } @@ -229,7 +229,7 @@ public static RuntimeException approxSourceException(Node node, Throwable cause) { final StackTraceElement[] elements = approxSourceStackTraceElement(node); @SuppressWarnings("serial") - RuntimeException exception = new RuntimeException(cause.getMessage(), cause) { + RuntimeException exception = new RuntimeException((cause == null) ? null : cause.getMessage(), cause) { @Override public final synchronized Throwable fillInStackTrace() { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java Mon May 13 17:11:31 2013 +0200 @@ -35,6 +35,7 @@ } public void put(FixedNode n, double value) { + assert value >= 0.0; nodeProbabilities.put(n, value); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Selects one object from a {@link CommitAllocationNode}. The object is identified by its + * {@link VirtualObjectNode}. + */ +public class AllocatedObjectNode extends FloatingNode implements Virtualizable { + + @Input private VirtualObjectNode virtualObject; + @Input private CommitAllocationNode commit; + + public AllocatedObjectNode(VirtualObjectNode virtualObject) { + super(StampFactory.exactNonNull(virtualObject.type())); + this.virtualObject = virtualObject; + } + + public VirtualObjectNode getVirtualObject() { + return virtualObject; + } + + public CommitAllocationNode getCommit() { + return commit; + } + + public void setCommit(CommitAllocationNode x) { + updateUsages(commit, x); + commit = x; + } + + @Override + public void virtualize(VirtualizerTool tool) { + tool.replaceWithVirtual(getVirtualObject()); + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}") +public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Simplifiable { + + @Input private final NodeInputList virtualObjects = new NodeInputList<>(this); + @Input private final NodeInputList values = new NodeInputList<>(this); + private List locks = new ArrayList<>(); + + public CommitAllocationNode() { + super(StampFactory.forVoid()); + } + + public List getVirtualObjects() { + return virtualObjects; + } + + public List getValues() { + return values; + } + + public List getLocks() { + return locks; + } + + @Override + public boolean verify() { + assertTrue(virtualObjects.size() == locks.size(), "lockCounts size doesn't match"); + int valueCount = 0; + for (VirtualObjectNode virtual : virtualObjects) { + valueCount += virtual.entryCount(); + } + assertTrue(values.size() == valueCount, "values size doesn't match"); + return super.verify(); + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + if (loweringType == LoweringType.AFTER_GUARDS) { + tool.getRuntime().lower(this, tool); + } + } + + @Override + public Node clone(Graph into) { + CommitAllocationNode clone = (CommitAllocationNode) super.clone(into); + clone.locks = new ArrayList<>(locks); + return clone; + } + + @Override + public void virtualize(VirtualizerTool tool) { + int pos = 0; + for (int i = 0; i < virtualObjects.size(); i++) { + VirtualObjectNode virtualObject = virtualObjects.get(i); + int entryCount = virtualObject.entryCount(); + tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), locks.get(i)); + pos += entryCount; + } + tool.delete(); + } + + @Override + public Map getDebugProperties(Map map) { + Map properties = super.getDebugProperties(map); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtual = virtualObjects.get(objIndex); + StringBuilder s = new StringBuilder(); + s.append(MetaUtil.toJavaName(virtual.type(), false)).append("["); + for (int i = 0; i < virtual.entryCount(); i++) { + ValueNode value = values.get(valuePos++); + s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id)); + } + s.append("]"); + if (locks.get(objIndex).length > 0) { + s.append(" locked(").append(Arrays.toString(locks.get(objIndex))).append(")"); + } + properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString()); + } + return properties; + } + + @Override + public void simplify(SimplifierTool tool) { + boolean[] used = new boolean[virtualObjects.size()]; + int usedCount = 0; + for (Node usage : usages()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = virtualObjects.indexOf(addObject.getVirtualObject()); + assert !used[index]; + used[index] = true; + usedCount++; + } + boolean progress; + do { + progress = false; + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + for (int i = 0; i < virtualObject.entryCount(); i++) { + int index = virtualObjects.indexOf(values.get(valuePos + i)); + if (index != -1 && !used[index]) { + progress = true; + used[index] = true; + usedCount++; + } + } + } + valuePos += virtualObject.entryCount(); + } + + } while (progress); + + if (usedCount < virtualObjects.size()) { + List newVirtualObjects = new ArrayList<>(usedCount); + List newLocks = new ArrayList<>(usedCount); + List newValues = new ArrayList<>(); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + newVirtualObjects.add(virtualObject); + newLocks.add(locks.get(objIndex)); + newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount())); + } + valuePos += virtualObject.entryCount(); + } + virtualObjects.clear(); + virtualObjects.addAll(newVirtualObjects); + locks.clear(); + locks.addAll(newLocks); + values.clear(); + values.addAll(newValues); + } + } + +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,14 +22,11 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import sun.misc.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") @@ -72,7 +69,7 @@ } @Override - public String fieldName(int index) { + public String entryName(int index) { return "[" + index + "]"; } @@ -143,17 +140,7 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { - StructuredGraph graph = (StructuredGraph) graph(); - ResolvedJavaType element = componentType(); - NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount(), graph), defaultValuesOnly, lockCount > 0)); - materializeNode.replaceAtUsages(newArray); - graph.addBeforeFixed(materializeNode, newArray); - if (!defaultValuesOnly) { - for (int i = 0; i < entryCount(); i++) { - graph.addBeforeFixed(materializeNode, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i)))); - } - } - graph.removeFixed(materializeNode); + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + return new AllocatedObjectNode(this); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -48,11 +46,9 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { - assert values.size() == 1; - assert lockCount == 0; - StructuredGraph graph = (StructuredGraph) graph(); - BoxNode valueOf = graph.add(new BoxNode(values.get(0), type(), boxingKind)); - graph.replaceFixedWithFixed(materializeNode, valueOf); + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + assert entries.length == 1; + assert locks.length == 0; + return new BoxNode(entries[0], type(), boxingKind); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,14 +22,11 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -@NodeInfo(nameTemplate = "VirtualInstance {p#type}") +@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}") public class VirtualInstanceNode extends VirtualObjectNode { private final ResolvedJavaType type; @@ -68,7 +65,7 @@ } @Override - public String fieldName(int index) { + public String entryName(int index) { return fields[index].getName(); } @@ -99,16 +96,7 @@ } @Override - public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { - StructuredGraph graph = (StructuredGraph) graph(); - NewInstanceNode newInstance = graph.add(new NewInstanceNode(type(), defaultValuesOnly, lockCount > 0)); - materializeNode.replaceAtUsages(newInstance); - graph.addBeforeFixed(materializeNode, newInstance); - if (!defaultValuesOnly) { - for (int i = 0; i < entryCount(); i++) { - graph.addBeforeFixed(materializeNode, graph.add(new StoreFieldNode(newInstance, field(i), values.get(i)))); - } - } - graph.removeFixed(materializeNode); + public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks) { + return new AllocatedObjectNode(this); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon May 13 17:11:31 2013 +0200 @@ -22,41 +22,68 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -@NodeInfo(nameTemplate = "VirtualObject {p#type}") public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable { public VirtualObjectNode() { super(StampFactory.virtual()); } + /** + * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is + * the array type (and not the component type). + */ public abstract ResolvedJavaType type(); + /** + * The number of entries this virtual object has. Either the number of fields or the number of + * array elements. + */ public abstract int entryCount(); + /** + * Returns the name of the entry at the given index. Only used for debugging purposes. + */ + public abstract String entryName(int i); + + /** + * If the given index denotes an entry in this virtual object, the index of this entry is + * returned. If no such entry can be found, this method returns -1. + */ + public abstract int entryIndexForOffset(long constantOffset); + + /** + * Returns the {@link Kind} of the entry at the given index. + */ + public abstract Kind entryKind(int index); + + /** + * Returns an exact duplicate of this virtual object node, which has not been added to the graph + * yet. + */ + public abstract VirtualObjectNode duplicate(); + + /** + * Specifies whether this virtual object has an object identity. If not, then the result of a + * comparison of two virtual objects is determined by comparing their contents. + */ + public boolean hasIdentity() { + return true; + } + + /** + * Returns a node that can be used to materialize this virtual object. If this returns an + * {@link AllocatedObjectNode} then this node will be attached to a {@link CommitAllocationNode} + * , otherwise the node will just be added to the graph. + */ + public abstract ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, int[] locks); + @Override public void generate(LIRGeneratorTool gen) { // nothing to do... } - - public abstract String fieldName(int i); - - public abstract void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount); - - public abstract int entryIndexForOffset(long constantOffset); - - public abstract Kind entryKind(int index); - - public abstract VirtualObjectNode duplicate(); - - public boolean hasIdentity() { - return true; - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Mon May 13 17:11:31 2013 +0200 @@ -22,14 +22,13 @@ */ package com.oracle.graal.phases.common; -import java.util.*; import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; @@ -49,6 +48,7 @@ public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); private final CustomCanonicalizer customCanonicalizer; + private final Iterable workingSet; public interface CustomCanonicalizer { @@ -60,12 +60,17 @@ } public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) { + this(customCanonicalizer, null); + } + + public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer, Iterable workingSet) { this.customCanonicalizer = customCanonicalizer; + this.workingSet = workingSet; } @Override protected void run(StructuredGraph graph, PhaseContext context) { - new Instance(context.getRuntime(), context.getAssumptions(), null, customCanonicalizer).run(graph); + new Instance(context.getRuntime(), context.getAssumptions(), workingSet, customCanonicalizer).run(graph); } public static class Instance extends Phase { @@ -78,7 +83,6 @@ private NodeWorkList workList; private Tool tool; - private List snapshotTemp; public Instance(MetaAccessProvider runtime, Assumptions assumptions) { this(runtime, assumptions, null, 0, null); @@ -110,7 +114,6 @@ this.runtime = runtime; this.customCanonicalizer = customCanonicalizer; this.initWorkingSet = workingSet; - this.snapshotTemp = new ArrayList<>(); } @Override @@ -129,19 +132,22 @@ } private void processWorkSet(StructuredGraph graph) { - graph.trackInputChange(new InputChangedListener() { + NodeChangedListener nodeChangedListener = new NodeChangedListener() { @Override - public void inputChanged(Node node) { + public void nodeChanged(Node node) { workList.addAgain(node); } - }); + }; + graph.trackInputChange(nodeChangedListener); + graph.trackUsagesDroppedZero(nodeChangedListener); for (Node n : workList) { processNode(n, graph); } graph.stopTrackingInputChange(); + graph.stopTrackingUsagesDroppedZero(); } private void processNode(Node node, StructuredGraph graph) { @@ -153,17 +159,9 @@ } int mark = graph.getMark(); if (!tryKillUnused(node)) { - node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); if (!tryCanonicalize(node, graph)) { tryInferStamp(node, graph); - } else { - for (Node in : snapshotTemp) { - if (in.isAlive() && in.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(in); - } - } } - snapshotTemp.clear(); } for (Node newNode : graph.getNewNodes(mark)) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -213,7 +213,7 @@ } @Override - public void afterSplit(BeginNode node) { + public void afterSplit(AbstractBeginNode node) { } @Override @@ -355,7 +355,7 @@ } } - private void registerControlSplitInfo(Node pred, BeginNode begin) { + private void registerControlSplitInfo(Node pred, AbstractBeginNode begin) { assert pred != null && begin != null; if (pred instanceof IfNode) { @@ -461,8 +461,8 @@ @Override protected void node(FixedNode node) { - if (node instanceof BeginNode) { - BeginNode begin = (BeginNode) node; + if (node instanceof AbstractBeginNode) { + AbstractBeginNode begin = (AbstractBeginNode) node; Node pred = node.predecessor(); if (pred != null) { @@ -501,8 +501,8 @@ GraphUtil.killWithUnusedFloatingInputs(compare); } } - } else if (node instanceof EndNode) { - EndNode endNode = (EndNode) node; + } else if (node instanceof AbstractEndNode) { + AbstractEndNode endNode = (AbstractEndNode) node; for (PhiNode phi : endNode.merge().phis()) { int index = endNode.merge().phiPredecessorIndex(endNode); ValueNode value = phi.valueAt(index); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Mon May 13 17:11:31 2013 +0200 @@ -27,17 +27,16 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; public class ConvertDeoptimizeToGuardPhase extends Phase { - private static BeginNode findBeginNode(Node startNode) { + private static AbstractBeginNode findBeginNode(Node startNode) { Node n = startNode; while (true) { - if (n instanceof BeginNode) { - return (BeginNode) n; + if (n instanceof AbstractBeginNode) { + return (AbstractBeginNode) n; } else { n = n.predecessor(); } @@ -58,17 +57,17 @@ new DeadCodeEliminationPhase().apply(graph); } - private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) { + private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) { if (deoptBegin instanceof MergeNode) { MergeNode mergeNode = (MergeNode) deoptBegin; Debug.log("Visiting %s followed by %s", mergeNode, deopt); - List begins = new ArrayList<>(); - for (EndNode end : mergeNode.forwardEnds()) { - BeginNode newBeginNode = findBeginNode(end); + List begins = new ArrayList<>(); + for (AbstractEndNode end : mergeNode.forwardEnds()) { + AbstractBeginNode newBeginNode = findBeginNode(end); assert !begins.contains(newBeginNode); begins.add(newBeginNode); } - for (BeginNode begin : begins) { + for (AbstractBeginNode begin : begins) { assert !begin.isDeleted(); visitDeoptBegin(begin, deopt, graph); } @@ -76,24 +75,20 @@ return; } else if (deoptBegin.predecessor() instanceof IfNode) { IfNode ifNode = (IfNode) deoptBegin.predecessor(); - BeginNode otherBegin = ifNode.trueSuccessor(); + AbstractBeginNode otherBegin = ifNode.trueSuccessor(); LogicNode conditionNode = ifNode.condition(); - if (!(conditionNode instanceof InstanceOfNode) && !(conditionNode instanceof InstanceOfDynamicNode)) { - // TODO The lowering currently does not support a FixedGuard as the usage of an - // InstanceOfNode. Relax this restriction. - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor())); - FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); - if (deoptBegin == ifNode.trueSuccessor()) { - graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor()); - } else { - graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor()); - } - Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); - FixedNode next = pred.next(); - pred.setNext(guard); - guard.setNext(next); - return; + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor())); + FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); + if (deoptBegin == ifNode.trueSuccessor()) { + graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor()); + } else { + graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor()); } + Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); + FixedNode next = pred.next(); + pred.setNext(guard); + guard.setNext(next); + return; } // We could not convert the control split - at least cut off control flow after the split. diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Mon May 13 17:11:31 2013 +0200 @@ -90,7 +90,7 @@ } @Override - public void afterSplit(BeginNode node) { + public void afterSplit(AbstractBeginNode node) { } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -52,8 +52,8 @@ private static void iterateSuccessors(NodeFlood flood) { for (Node current : flood) { - if (current instanceof EndNode) { - EndNode end = (EndNode) current; + if (current instanceof AbstractEndNode) { + AbstractEndNode end = (AbstractEndNode) current; flood.add(end.merge()); } else { for (Node successor : current.successors()) { @@ -64,7 +64,7 @@ } private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) { - for (EndNode node : graph.getNodes(EndNode.class)) { + for (AbstractEndNode node : graph.getNodes(AbstractEndNode.class)) { if (!flood.isMarked(node)) { MergeNode merge = node.merge(); if (merge != null && flood.isMarked(merge)) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Mon May 13 17:11:31 2013 +0200 @@ -116,16 +116,10 @@ } Collection hits = new LinkedList<>(); for (GuardNode guard : merge.guards()) { - if (guard.dependencies().size() != 1) { - continue; - } - for (EndNode end : merge.forwardEnds()) { - BeginNode begin = BeginNode.prevBegin(end); + for (AbstractEndNode end : merge.forwardEnds()) { + AbstractBeginNode begin = AbstractBeginNode.prevBegin(end); boolean found = false; for (GuardNode predecessorGuard : begin.guards()) { - if (predecessorGuard.dependencies().size() != 1) { - continue; - } if (guard.condition() == predecessorGuard.condition() && guard.negated() == predecessorGuard.negated()) { hits.add(guard); found = true; @@ -140,8 +134,8 @@ Graph graph = merge.graph(); for (GuardNode guard : hits) { PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null)); - for (EndNode otherEnd : merge.forwardEnds()) { - phi.addInput(graph.unique(new GuardNode(guard.condition(), BeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated()))); + for (AbstractEndNode otherEnd : merge.forwardEnds()) { + phi.addInput(graph.unique(new GuardNode(guard.condition(), AbstractBeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated()))); } guard.replaceAndDelete(phi); metricPRGuardsEliminatedAtMerge.increment(); @@ -152,11 +146,8 @@ private static boolean eliminateAtControlSplit(ControlSplitNode controlSplit) { Map> conditionToGuard = new HashMap<>(); for (Node successor : controlSplit.successors()) { - BeginNode begin = (BeginNode) successor; + AbstractBeginNode begin = (AbstractBeginNode) successor; for (GuardNode guard : begin.guards()) { - if (guard.dependencies().size() != 1) { - continue; - } Condition condition = new Condition(guard.condition(), guard.negated()); Collection guards = conditionToGuard.get(condition); if (guards == null) { @@ -175,9 +166,9 @@ } DeoptimizationReason reason = null; DeoptimizationAction action = DeoptimizationAction.None; - Set begins = new HashSet<>(3); + Set begins = new HashSet<>(3); for (GuardNode guard : guards) { - BeginNode begin = (BeginNode) guard.dependencies().first(); + AbstractBeginNode begin = (AbstractBeginNode) guard.getGuard(); begins.add(begin); if (guard.action().ordinal() > action.ordinal()) { action = guard.action(); @@ -191,7 +182,7 @@ if (begins.size() == controlSplit.successors().count()) { hits = true; Condition condition = entry.getKey(); - GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, BeginNode.prevBegin(controlSplit), reason, action, condition.negated)); + GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, AbstractBeginNode.prevBegin(controlSplit), reason, action, condition.negated)); for (GuardNode guard : guards) { guard.replaceAndDelete(newGuard); metricPRGuardsEliminatedAtSplit.increment(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.phases.common; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.phases.*; + +public class ExpandLogicPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (LogicBinaryNode logic : graph.getNodes(LogicBinaryNode.class)) { + processBinary(logic); + } + assert graph.getNodes(LogicBinaryNode.class).isEmpty(); + } + + private static void processBinary(LogicBinaryNode binary) { + while (binary.usages().isNotEmpty()) { + Node usage = binary.usages().first(); + if (usage instanceof LogicBinaryNode) { + processBinary((LogicBinaryNode) usage); + } else if (usage instanceof IfNode) { + if (binary instanceof LogicConjunctionNode) { + processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, false); + } else if (binary instanceof LogicDisjunctionNode) { + processIf(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (IfNode) usage, true); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else if (usage instanceof ConditionalNode) { + if (binary instanceof LogicConjunctionNode) { + processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage, false); + } else if (binary instanceof LogicDisjunctionNode) { + processConditional(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (ConditionalNode) usage, true); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + binary.safeDelete(); + } + + private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, boolean negateTargets) { + AbstractBeginNode trueTarget = negateTargets ? ifNode.falseSuccessor() : ifNode.trueSuccessor(); + AbstractBeginNode falseTarget = negateTargets ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); + double p = Math.sqrt(ifNode.probability(trueTarget)); + ifNode.clearSuccessors(); + Graph graph = ifNode.graph(); + MergeNode falseTargetMerge = graph.add(new MergeNode()); + falseTargetMerge.setNext(falseTarget); + EndNode firstFalseEnd = graph.add(new EndNode()); + EndNode secondFalseEnd = graph.add(new EndNode()); + falseTargetMerge.addForwardEnd(firstFalseEnd); + falseTargetMerge.addForwardEnd(secondFalseEnd); + AbstractBeginNode firstFalseTarget = AbstractBeginNode.begin(firstFalseEnd); + AbstractBeginNode secondFalseTarget = AbstractBeginNode.begin(secondFalseEnd); + AbstractBeginNode secondIf = AbstractBeginNode.begin(graph.add(new IfNode(y, yNegated ? firstFalseTarget : trueTarget, yNegated ? trueTarget : firstFalseTarget, yNegated ? 1 - p : p))); + IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondFalseTarget : secondIf, xNegated ? secondIf : secondFalseTarget, xNegated ? 1 - p : p)); + ifNode.replaceAtPredecessor(firstIf); + ifNode.safeDelete(); + } + + private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional, boolean negateTargets) { + ValueNode trueTarget = negateTargets ? conditional.falseValue() : conditional.trueValue(); + ValueNode falseTarget = negateTargets ? conditional.trueValue() : conditional.falseValue(); + Graph graph = conditional.graph(); + ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget)); + ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? falseTarget : secondConditional, xNegated ? secondConditional : falseTarget)); + conditional.replaceAndDelete(firstConditional); + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; @@ -36,7 +37,7 @@ private static class MemoryMap { - private IdentityHashMap lastMemorySnapshot; + private IdentityHashMap lastMemorySnapshot; public MemoryMap(MemoryMap memoryMap) { lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); @@ -51,7 +52,7 @@ lastMemorySnapshot = new IdentityHashMap<>(); } - private ValueNode getLastLocationAccess(Object locationIdentity) { + private ValueNode getLastLocationAccess(LocationIdentity locationIdentity) { ValueNode lastLocationAccess; if (locationIdentity == LocationNode.FINAL_LOCATION) { return null; @@ -73,50 +74,51 @@ @Override protected void run(StructuredGraph graph) { - Map> modifiedInLoops = new IdentityHashMap<>(); - ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet<>(), null); + Map> modifiedInLoops = new IdentityHashMap<>(); + ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet(), null); ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops), graph.start(), new MemoryMap(graph.start()), null); } - private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure> { + private static class CollectMemoryCheckpointsClosure extends NodeIteratorClosure> { - private final Map> modifiedInLoops; + private final Map> modifiedInLoops; - public CollectMemoryCheckpointsClosure(Map> modifiedInLoops) { + public CollectMemoryCheckpointsClosure(Map> modifiedInLoops) { this.modifiedInLoops = modifiedInLoops; } @Override - protected void processNode(FixedNode node, Set currentState) { + protected Set processNode(FixedNode node, Set currentState) { if (node instanceof MemoryCheckpoint) { - for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) { + for (LocationIdentity identity : ((MemoryCheckpoint) node).getLocationIdentities()) { currentState.add(identity); } } + return currentState; } @Override - protected Set merge(MergeNode merge, List> states) { - Set result = new HashSet<>(); - for (Set other : states) { + protected Set merge(MergeNode merge, List> states) { + Set result = new HashSet<>(); + for (Set other : states) { result.addAll(other); } return result; } @Override - protected Set afterSplit(BeginNode node, Set oldState) { + protected Set afterSplit(AbstractBeginNode node, Set oldState) { return new HashSet<>(oldState); } @Override - protected Map> processLoop(LoopBeginNode loop, Set initialState) { - LoopInfo> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<>()); - Set modifiedLocations = new HashSet<>(); - for (Set end : loopInfo.endStates.values()) { + protected Map> processLoop(LoopBeginNode loop, Set initialState) { + LoopInfo> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet()); + Set modifiedLocations = new HashSet<>(); + for (Set end : loopInfo.endStates.values()) { modifiedLocations.addAll(end); } - for (Set exit : loopInfo.exitStates.values()) { + for (Set exit : loopInfo.exitStates.values()) { exit.addAll(modifiedLocations); exit.addAll(initialState); } @@ -129,23 +131,24 @@ private static class FloatingReadClosure extends NodeIteratorClosure { - private final Map> modifiedInLoops; + private final Map> modifiedInLoops; - public FloatingReadClosure(Map> modifiedInLoops) { + public FloatingReadClosure(Map> modifiedInLoops) { this.modifiedInLoops = modifiedInLoops; } @Override - protected void processNode(FixedNode node, MemoryMap state) { + protected MemoryMap processNode(FixedNode node, MemoryMap state) { if (node instanceof FloatableAccessNode) { processFloatable((FloatableAccessNode) node, state); } else if (node instanceof MemoryCheckpoint) { processCheckpoint((MemoryCheckpoint) node, state); } + return state; } private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { - for (Object identity : checkpoint.getLocationIdentities()) { + for (LocationIdentity identity : checkpoint.getLocationIdentities()) { if (identity == LocationNode.ANY_LOCATION) { state.lastMemorySnapshot.clear(); } @@ -154,20 +157,18 @@ } private static void processFloatable(FloatableAccessNode accessNode, MemoryMap state) { - StructuredGraph graph = (StructuredGraph) accessNode.graph(); + StructuredGraph graph = accessNode.graph(); assert accessNode.getNullCheck() == false; - Object locationIdentity = accessNode.location().locationIdentity(); + LocationIdentity locationIdentity = accessNode.location().getLocationIdentity(); if (locationIdentity != LocationNode.ANY_LOCATION) { ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess); floatingNode.setNullCheck(accessNode.getNullCheck()); ValueAnchorNode anchor = null; - for (GuardNode guard : accessNode.dependencies().filter(GuardNode.class)) { - if (anchor == null) { - anchor = graph.add(new ValueAnchorNode()); - graph.addAfterFixed(accessNode, anchor); - } - anchor.addAnchoredNode(guard); + GuardingNode guard = accessNode.getGuard(); + if (guard != null) { + anchor = graph.add(new ValueAnchorNode(guard.asNode())); + graph.addAfterFixed(accessNode, anchor); } graph.replaceFixedWithFloating(accessNode, floatingNode); } @@ -177,13 +178,13 @@ protected MemoryMap merge(MergeNode merge, List states) { MemoryMap newState = new MemoryMap(); - Set keys = new HashSet<>(); + Set keys = new HashSet<>(); for (MemoryMap other : states) { keys.addAll(other.lastMemorySnapshot.keySet()); } assert !keys.contains(LocationNode.FINAL_LOCATION); - for (Object key : keys) { + for (LocationIdentity key : keys) { int mergedStatesCount = 0; boolean isPhi = false; ValueNode merged = null; @@ -214,7 +215,7 @@ } @Override - protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) { + protected MemoryMap afterSplit(AbstractBeginNode node, MemoryMap oldState) { MemoryMap result = new MemoryMap(oldState); if (node.predecessor() instanceof InvokeWithExceptionNode) { /* @@ -225,7 +226,7 @@ * needs to choose by putting in the location identity on both successors. */ InvokeWithExceptionNode checkpoint = (InvokeWithExceptionNode) node.predecessor(); - for (Object identity : checkpoint.getLocationIdentities()) { + for (LocationIdentity identity : checkpoint.getLocationIdentities()) { result.lastMemorySnapshot.put(identity, node); } } @@ -234,15 +235,15 @@ @Override protected Map processLoop(LoopBeginNode loop, MemoryMap initialState) { - Set modifiedLocations = modifiedInLoops.get(loop); + Set modifiedLocations = modifiedInLoops.get(loop); if (modifiedLocations.contains(LocationNode.ANY_LOCATION)) { // create phis for all locations if ANY is modified in the loop modifiedLocations = new HashSet<>(modifiedLocations); modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet()); } - Map phis = new HashMap<>(); - for (Object location : modifiedLocations) { + Map phis = new HashMap<>(); + for (LocationIdentity location : modifiedLocations) { PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop, location)); phi.addInput(initialState.getLastLocationAccess(location)); phis.put(location, phi); @@ -253,8 +254,8 @@ for (Map.Entry entry : loopInfo.endStates.entrySet()) { int endIndex = loop.phiPredecessorIndex(entry.getKey()); - for (Map.Entry phiEntry : phis.entrySet()) { - Object key = phiEntry.getKey(); + for (Map.Entry phiEntry : phis.entrySet()) { + LocationIdentity key = phiEntry.getKey(); PhiNode phi = phiEntry.getValue(); phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key)); } @@ -262,10 +263,10 @@ for (Map.Entry entry : loopInfo.exitStates.entrySet()) { LoopExitNode exit = entry.getKey(); MemoryMap state = entry.getValue(); - for (Object location : modifiedLocations) { + for (LocationIdentity location : modifiedLocations) { ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location); if (lastAccessAtExit != null) { - state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, (StructuredGraph) loop.graph())); + state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, loop.graph())); } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Mon May 13 17:11:31 2013 +0200 @@ -27,83 +27,51 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; public class FrameStateAssignmentPhase extends Phase { - private static class FrameStateAssignmentState { - - private FrameState framestate; - - public FrameStateAssignmentState(FrameState framestate) { - this.framestate = framestate; - } + private static class FrameStateAssignementClosure extends NodeIteratorClosure { - public FrameState getFramestate() { - return framestate; - } + @Override + protected FrameState processNode(FixedNode node, FrameState currentState) { + if (node instanceof DeoptimizingNode) { + DeoptimizingNode deopt = (DeoptimizingNode) node; + if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) { + deopt.setDeoptimizationState(currentState); + } + } - public void setFramestate(FrameState framestate) { - assert framestate != null; - this.framestate = framestate; + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + if (stateSplit.stateAfter() != null) { + FrameState newState = stateSplit.stateAfter(); + stateSplit.setStateAfter(null); + return newState; + } + } + return currentState; } @Override - public String toString() { - return "FrameStateAssignementState: " + framestate; - } - } - - private static class FrameStateAssignementClosure extends BlockIteratorClosure { - - @Override - protected void processBlock(Block block, FrameStateAssignmentState currentState) { - FixedNode node = block.getBeginNode(); - while (node != null) { - if (node instanceof DeoptimizingNode) { - DeoptimizingNode deopt = (DeoptimizingNode) node; - if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) { - deopt.setDeoptimizationState(currentState.getFramestate()); - } - } - - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - if (stateSplit.stateAfter() != null) { - currentState.setFramestate(stateSplit.stateAfter()); - stateSplit.setStateAfter(null); - } - } - - if (node instanceof FixedWithNextNode) { - node = ((FixedWithNextNode) node).next(); - } else { - node = null; - } + protected FrameState merge(MergeNode merge, List states) { + if (merge.stateAfter() != null) { + return merge.stateAfter(); } + return singleFrameState(merge, states); } @Override - protected FrameStateAssignmentState merge(Block mergeBlock, List states) { - MergeNode merge = (MergeNode) mergeBlock.getBeginNode(); - if (merge.stateAfter() != null) { - return new FrameStateAssignmentState(merge.stateAfter()); - } - return new FrameStateAssignmentState(singleFrameState(states)); + protected FrameState afterSplit(AbstractBeginNode node, FrameState oldState) { + return oldState; } @Override - protected FrameStateAssignmentState cloneState(FrameStateAssignmentState oldState) { - return new FrameStateAssignmentState(oldState.getFramestate()); - } - - @Override - protected List processLoop(Loop loop, FrameStateAssignmentState initialState) { - return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates; + protected Map processLoop(LoopBeginNode loop, FrameState initialState) { + return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; } } @@ -111,8 +79,7 @@ @Override protected void run(StructuredGraph graph) { assert checkFixedDeopts(graph); - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignmentState(null), null); + ReentrantNodeIterator.apply(new FrameStateAssignementClosure(), graph.start(), null, null); } private static boolean checkFixedDeopts(StructuredGraph graph) { @@ -125,15 +92,34 @@ return true; } - private static FrameState singleFrameState(List states) { - Iterator it = states.iterator(); - assert it.hasNext(); - FrameState first = it.next().getFramestate(); - while (it.hasNext()) { - if (first != it.next().getFramestate()) { + private static FrameState singleFrameState(@SuppressWarnings("unused") MergeNode merge, List states) { + if (states.size() == 0) { + return null; + } + FrameState firstState = states.get(0); + FrameState singleState = firstState; + if (singleState == null) { + return null; + } + int singleBci = singleState.bci; + for (int i = 1; i < states.size(); ++i) { + FrameState cur = states.get(i); + if (cur == null) { return null; } + + if (cur != singleState) { + singleState = null; + } + + if (cur.bci != singleBci) { + singleBci = FrameState.INVALID_FRAMESTATE_BCI; + } + } - return first; + if (singleState != null) { + return singleState; + } + return null; } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Mon May 13 17:11:31 2013 +0200 @@ -114,8 +114,7 @@ private void processAccess(Access access) { GuardNode guard = nullGuarded.get(access.object()); if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) { - NodeInputList dependencies = ((ValueNode) access).dependencies(); - dependencies.remove(guard); + access.setGuard(guard.getGuard()); Access fixedAccess = access; if (access instanceof FloatingAccessNode) { fixedAccess = ((FloatingAccessNode) access).asFixedNode(); @@ -142,7 +141,7 @@ private boolean isImplicitNullCheck(LocationNode location) { if (location instanceof ConstantLocationNode) { - return ((ConstantLocationNode) location).displacement() < implicitNullCheckLimit; + return ((ConstantLocationNode) location).getDisplacement() < implicitNullCheckLimit; } else { return false; } @@ -170,12 +169,12 @@ } private void lowerToIf(GuardNode guard) { - StructuredGraph graph = (StructuredGraph) guard.graph(); - BeginNode fastPath = graph.add(new BeginNode()); + StructuredGraph graph = guard.graph(); + AbstractBeginNode fastPath = graph.add(new BeginNode()); DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason())); - BeginNode deoptBranch = BeginNode.begin(deopt); - BeginNode trueSuccessor; - BeginNode falseSuccessor; + AbstractBeginNode deoptBranch = AbstractBeginNode.begin(deopt); + AbstractBeginNode trueSuccessor; + AbstractBeginNode falseSuccessor; insertLoopExits(deopt); if (guard.negated()) { trueSuccessor = deoptBranch; @@ -193,11 +192,14 @@ IsNullNode isNull = (IsNullNode) guard.condition(); NullCheckNode nullCheck = guard.graph().add(new NullCheckNode(isNull.object())); replaceCurrent(nullCheck); + if (isNull.usages().isEmpty()) { + isNull.safeDelete(); + } } private void insertLoopExits(DeoptimizeNode deopt) { Loop loop = block.getLoop(); - StructuredGraph graph = (StructuredGraph) deopt.graph(); + StructuredGraph graph = deopt.graph(); while (loop != null) { LoopExitNode exit = graph.add(new LoopExitNode(loop.loopBegin())); graph.addBeforeFixed(deopt, exit); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon May 13 17:11:31 2013 +0200 @@ -574,7 +574,7 @@ return result; } - private void queueMerge(EndNode end) { + private void queueMerge(AbstractEndNode end) { MergeNode merge = end.merge(); if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) { queuedNodes.mark(merge); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon May 13 17:11:31 2013 +0200 @@ -42,6 +42,7 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.common.InliningPhase.InliningData; public class InliningUtil { @@ -275,7 +276,7 @@ } protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, InlineableElement inlineable, Assumptions assumptions, boolean receiverNullCheck) { - StructuredGraph graph = (StructuredGraph) invoke.asNode().graph(); + StructuredGraph graph = invoke.asNode().graph(); if (inlineable instanceof StructuredGraph) { StructuredGraph calleeGraph = (StructuredGraph) inlineable; InliningUtil.inline(invoke, calleeGraph, receiverNullCheck); @@ -484,16 +485,19 @@ private final List concretes; private final double[] methodProbabilities; private final double maximumMethodProbability; + private final ArrayList typesToConcretes; private final ArrayList ptypes; - private final int[] typesToConcretes; + private final ArrayList concretesProbabilities; private final double notRecordedTypeProbability; private final InlineableElement[] inlineableElements; - public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList ptypes, int[] typesToConcretes, double notRecordedTypeProbability) { + public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes, + ArrayList typesToConcretes, double notRecordedTypeProbability) { super(invoke); - assert concretes.size() > 0 && concretes.size() <= ptypes.size() : "must have at least one method but no more than types methods"; - assert ptypes.size() == typesToConcretes.length : "array lengths must match"; + assert concretes.size() > 0 : "must have at least one method"; + assert ptypes.size() == typesToConcretes.size() : "array lengths must match"; + this.concretesProbabilities = concretesProbabilities; this.concretes = concretes; this.ptypes = ptypes; this.typesToConcretes = typesToConcretes; @@ -603,7 +607,7 @@ } // create one separate block for each invoked method - BeginNode[] successors = new BeginNode[numberOfMethods + 1]; + AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1]; for (int i = 0; i < numberOfMethods; i++) { successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true); } @@ -615,7 +619,7 @@ } else { unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)); } - successors[successors.length - 1] = BeginNode.begin(unknownTypeSux); + successors[successors.length - 1] = AbstractBeginNode.begin(unknownTypeSux); // replace the invoke exception edge if (invoke instanceof InvokeWithExceptionNode) { @@ -629,7 +633,7 @@ assert invoke.asNode().isAlive(); // replace the invoke with a switch on the type of the actual receiver - createDispatchOnTypeBeforeInvoke(graph, successors, false); + boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime); assert invoke.next() == continuation; invoke.setNext(null); @@ -641,12 +645,18 @@ // do the actual inlining for every invoke for (int i = 0; i < numberOfMethods; i++) { - BeginNode node = successors[i]; + AbstractBeginNode node = successors[i]; Invoke invokeForInlining = (Invoke) node.next(); - ResolvedJavaType commonType = getLeastCommonType(i); + ResolvedJavaType commonType; + if (methodDispatch) { + commonType = concretes.get(i).getDeclaringClass(); + } else { + commonType = getLeastCommonType(i); + } + ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver(); - boolean exact = getTypeCount(i) == 1; + boolean exact = (getTypeCount(i) == 1 && !methodDispatch); PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); @@ -657,6 +667,7 @@ if (shouldFallbackToInvoke()) { replacementNodes.add(null); } + if (GraalOptions.OptTailDuplication) { /* * We might want to perform tail duplication at the merge after a type switch, if @@ -676,15 +687,15 @@ if (opportunities > 0) { metricInliningTailDuplication.increment(); Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes); + TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, new HighTierContext(runtime, assumptions, replacements)); } } } private int getTypeCount(int concreteMethodIndex) { int count = 0; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { + for (int i = 0; i < typesToConcretes.size(); i++) { + if (typesToConcretes.get(i) == concreteMethodIndex) { count++; } } @@ -693,8 +704,8 @@ private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) { ResolvedJavaType commonType = null; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { + for (int i = 0; i < typesToConcretes.size(); i++) { + if (typesToConcretes.get(i) == concreteMethodIndex) { if (commonType == null) { commonType = ptypes.get(i).getType(); } else { @@ -717,31 +728,73 @@ private void inlineSingleMethod(StructuredGraph graph, Assumptions assumptions) { assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; - BeginNode calleeEntryNode = graph.add(new BeginNode()); + AbstractBeginNode calleeEntryNode = graph.add(new BeginNode()); - BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); - BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux}; - createDispatchOnTypeBeforeInvoke(graph, successors, false); + AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); + AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux}; + createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime); calleeEntryNode.setNext(invoke.asNode()); inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false); } - private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) { - assert ptypes.size() > 1; + private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) { + assert ptypes.size() >= 1; Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind(); LoadHubNode hub = graph.add(new LoadHubNode(((MethodCallTargetNode) invoke.callTarget()).receiver(), hubKind)); graph.addBeforeFixed(invoke.asNode(), hub); + if (!invokeIsOnlySuccessor && chooseMethodDispatch()) { + assert successors.length == concretes.size() + 1; + assert concretes.size() > 0; + Debug.log("Method check cascade with %d methods", concretes.size()); + + ValueNode[] constantMethods = new ValueNode[concretes.size()]; + double[] probability = new double[concretes.size()]; + for (int i = 0; i < concretes.size(); ++i) { + ResolvedJavaMethod firstMethod = concretes.get(i); + Constant firstMethodConstant = firstMethod.getEncoding(); + + ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, runtime, graph); + constantMethods[i] = firstMethodConstantNode; + double concretesProbability = concretesProbabilities.get(i); + assert concretesProbability >= 0.0; + probability[i] = concretesProbability; + if (i > 0) { + double prevProbability = probability[i - 1]; + if (prevProbability == 1.0) { + probability[i] = 1.0; + } else { + probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability))); + } + } + } + + FixedNode lastSucc = successors[concretes.size()]; + for (int i = concretes.size() - 1; i >= 0; --i) { + LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind())); + CompareNode methodCheck = CompareNode.createCompareNode(Condition.EQ, method, constantMethods[i]); + IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i])); + method.setNext(ifNode); + lastSucc = method; + } + + FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor(); + pred.setNext(lastSucc); + return true; + } else { + Debug.log("Type switch with %d types", concretes.size()); + } + ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()]; double[] keyProbabilities = new double[ptypes.size() + 1]; int[] keySuccessors = new int[ptypes.size() + 1]; for (int i = 0; i < ptypes.size(); i++) { keys[i] = ptypes.get(i).getType(); keyProbabilities[i] = ptypes.get(i).getProbability(); - keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes[i]; + keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i); assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux"; } keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability; @@ -750,15 +803,60 @@ TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors)); FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor(); pred.setNext(typeSwitch); + return false; + } + + private boolean chooseMethodDispatch() { + for (ResolvedJavaMethod concrete : concretes) { + if (!concrete.isInVirtualMethodTable()) { + return false; + } + } + + if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) { + // Always chose method dispatch if there is a single concrete method and the call + // site is megamorphic. + return true; + } + + if (concretes.size() == ptypes.size()) { + // Always prefer types over methods if the number of types is smaller than the + // number of methods. + return false; + } + + return chooseMethodDispatchCostBased(); } - private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, - boolean useForInlining) { + private boolean chooseMethodDispatchCostBased() { + double remainder = 1.0 - this.notRecordedTypeProbability; + double costEstimateMethodDispatch = remainder; + for (int i = 0; i < concretes.size(); ++i) { + if (i != 0) { + costEstimateMethodDispatch += remainder; + } + remainder -= concretesProbabilities.get(i); + } + + double costEstimateTypeDispatch = 0.0; + remainder = 1.0; + for (int i = 0; i < ptypes.size(); ++i) { + if (i != 0) { + costEstimateTypeDispatch += remainder; + } + remainder -= ptypes.get(i).getProbability(); + } + costEstimateTypeDispatch += notRecordedTypeProbability; + return costEstimateMethodDispatch < costEstimateTypeDispatch; + } + + private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, + PhiNode exceptionObjectPhi, boolean useForInlining) { Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining); - BeginNode calleeEntryNode = graph.add(new BeginNode()); + AbstractBeginNode calleeEntryNode = graph.add(new BeginNode()); calleeEntryNode.setNext(duplicatedInvoke.asNode()); - EndNode endNode = graph.add(new EndNode()); + AbstractEndNode endNode = graph.add(new EndNode()); duplicatedInvoke.setNext(endNode); returnMerge.addForwardEnd(endNode); @@ -793,7 +891,7 @@ // set new state (pop old exception object, push new one) newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge)); - EndNode endNode = graph.add(new EndNode()); + AbstractEndNode endNode = graph.add(new EndNode()); newExceptionEdge.setNext(endNode); exceptionMerge.addForwardEnd(endNode); exceptionObjectPhi.addInput(newExceptionEdge); @@ -812,11 +910,11 @@ } } - private void tryToDevirtualizeSingleMethod(StructuredGraph graph) { - devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0)); + private void tryToDevirtualizeSingleMethod(StructuredGraph graph, MetaAccessProvider runtime) { + devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0), runtime); } - private void tryToDevirtualizeMultipleMethods(StructuredGraph graph) { + private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider runtime) { MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget(); if (methodCallTarget.invokeKind() == InvokeKind.Interface) { ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod(); @@ -827,19 +925,19 @@ if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) { ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod); if (baseClassTargetMethod != null) { - devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod)); + devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), runtime); } } } } - private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target) { + private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider runtime) { InliningUtil.receiverNullCheck(invoke); - BeginNode invocationEntry = graph.add(new BeginNode()); - BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); - BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux}; - createDispatchOnTypeBeforeInvoke(graph, successors, true); + AbstractBeginNode invocationEntry = graph.add(new BeginNode()); + AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); + AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux}; + createDispatchOnTypeBeforeInvoke(graph, successors, true, runtime); invocationEntry.setNext(invoke.asNode()); ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver(); @@ -848,8 +946,8 @@ replaceInvokeCallTarget(invoke, graph, kind, target); } - private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) { - return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated))); + private static AbstractBeginNode createUnknownTypeSuccessor(StructuredGraph graph) { + return AbstractBeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated))); } @Override @@ -915,7 +1013,6 @@ if (!checkInvokeConditions(invoke)) { return null; } - ResolvedJavaMethod caller = getCaller(invoke); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); @@ -958,7 +1055,7 @@ } // type check based inlining - return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, caller, holder, targetMethod, optimisticOpts); + return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts); } private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, @@ -978,27 +1075,27 @@ return new ExactInlineInfo(invoke, targetMethod); } - private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod caller, ResolvedJavaType holder, - ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { - ProfilingInfo profilingInfo = caller.getProfilingInfo(); - JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); - if (typeProfile == null) { + private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { + ValueNode receiver = invoke.callTarget().arguments().get(0); + if (receiver instanceof TypeProfileProxyNode) { + TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver; + typeProfile = typeProfileProxyNode.getProfile(); + } else { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no type profile exists"); } - ProfiledType[] rawProfiledTypes = typeProfile.getTypes(); - ArrayList ptypes = getCompatibleTypes(rawProfiledTypes, holder); - if (ptypes == null || ptypes.size() <= 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remained after filtering (%d types were recorded)", rawProfiledTypes.length); + ProfiledType[] ptypes = typeProfile.getTypes(); + if (ptypes == null || ptypes.length <= 0) { + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types in profile"); } double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.size() == 1 && notRecordedTypeProbability == 0) { + if (ptypes.length == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls()) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining monomorphic calls is disabled"); } - ResolvedJavaType type = ptypes.get(0).getType(); + ResolvedJavaType type = ptypes[0].getType(); ResolvedJavaMethod concrete = type.resolveMethod(targetMethod); if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { return null; @@ -1008,59 +1105,83 @@ invoke.setPolymorphic(true); if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.size()); + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); } if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { // due to filtering impossible types, notRecordedTypeProbability can be > 0 although // the number of types is lower than what can be recorded in a type profile - return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.size(), + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); } - // determine concrete methods and map type to specific method + // Find unique methods and their probabilities. ArrayList concreteMethods = new ArrayList<>(); - int[] typesToConcretes = new int[ptypes.size()]; - for (int i = 0; i < ptypes.size(); i++) { - ResolvedJavaMethod concrete = ptypes.get(i).getType().resolveMethod(targetMethod); - + ArrayList concreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < ptypes.length; i++) { + ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod); int index = concreteMethods.indexOf(concrete); + double curProbability = ptypes[i].getProbability(); if (index < 0) { index = concreteMethods.size(); concreteMethods.add(concrete); + concreteMethodsProbabilities.add(curProbability); + } else { + concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability); } - typesToConcretes[i] = index; } if (concreteMethods.size() > maxNumberOfMethods) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods); } + // Clear methods that fall below the threshold. + if (notRecordedTypeProbability > 0) { + ArrayList newConcreteMethods = new ArrayList<>(); + ArrayList newConcreteMethodsProbabilities = new ArrayList<>(); + for (int i = 0; i < concreteMethods.size(); ++i) { + if (concreteMethodsProbabilities.get(i) >= GraalOptions.MegamorphicInliningMinMethodProbability) { + newConcreteMethods.add(concreteMethods.get(i)); + newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i)); + } + } + + if (newConcreteMethods.size() == 0) { + // No method left that is worth inlining. + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); + } + + concreteMethods = newConcreteMethods; + concreteMethodsProbabilities = newConcreteMethodsProbabilities; + } + + // Clean out types whose methods are no longer available. + ArrayList usedTypes = new ArrayList<>(); + ArrayList typesToConcretes = new ArrayList<>(); + for (ProfiledType type : ptypes) { + ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod); + int index = concreteMethods.indexOf(concrete); + if (index == -1) { + notRecordedTypeProbability += type.getProbability(); + } else { + usedTypes.add(type); + typesToConcretes.add(index); + } + } + + if (usedTypes.size() == 0) { + // No type left that is worth checking for. + return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); + } + for (ResolvedJavaMethod concrete : concreteMethods) { if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); } } - return new MultiTypeGuardInlineInfo(invoke, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability); + return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability); } } - private static ArrayList getCompatibleTypes(ProfiledType[] types, ResolvedJavaType holder) { - ArrayList result = new ArrayList<>(); - for (int i = 0; i < types.length; i++) { - ProfiledType ptype = types[i]; - ResolvedJavaType type = ptype.getType(); - assert !type.isInterface() && (type.isArray() || !Modifier.isAbstract(type.getModifiers())) : type; - if (!GraalOptions.OptFilterProfiledTypes || holder.isAssignableFrom(type)) { - result.add(ptype); - } - } - return result; - } - - private static ResolvedJavaMethod getCaller(Invoke invoke) { - return invoke.stateAfter().method(); - } - private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { // to avoid that floating reads on receiver fields float above the type check return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor)); @@ -1138,7 +1259,7 @@ */ public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { NodeInputList parameters = invoke.callTarget().arguments(); - StructuredGraph graph = (StructuredGraph) invoke.asNode().graph(); + StructuredGraph graph = invoke.asNode().graph(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter.isAlive(); @@ -1166,7 +1287,7 @@ } } // ensure proper anchoring of things that were anchored to the StartNode - replacements.put(entryPointNode, BeginNode.prevBegin(invoke.asNode())); + replacements.put(entryPointNode, AbstractBeginNode.prevBegin(invoke.asNode())); assert invoke.asNode().successors().first() != null : invoke; assert invoke.asNode().predecessor() != null; @@ -1270,7 +1391,7 @@ public static void receiverNullCheck(Invoke invoke) { MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); - StructuredGraph graph = (StructuredGraph) callTarget.graph(); + StructuredGraph graph = callTarget.graph(); NodeInputList parameters = callTarget.arguments(); ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -24,7 +24,7 @@ import java.util.*; -import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.Graph.NodeChangedListener; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.phases.*; @@ -49,7 +49,7 @@ } } - private static class Listener implements InputChangedListener { + private static class Listener implements NodeChangedListener { private final Set canonicalizationRoots; @@ -58,7 +58,7 @@ } @Override - public void inputChanged(Node node) { + public void nodeChanged(Node node) { canonicalizationRoots.add(node); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Mon May 13 17:11:31 2013 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.Lowerable.LoweringType; import com.oracle.graal.phases.*; @@ -45,12 +46,12 @@ final class LoweringToolImpl implements LoweringTool { private final PhaseContext context; - private final FixedNode guardAnchor; + private final GuardingNode guardAnchor; private final NodeBitMap activeGuards; private FixedWithNextNode lastFixedNode; private ControlFlowGraph cfg; - public LoweringToolImpl(PhaseContext context, FixedNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) { + public LoweringToolImpl(PhaseContext context, GuardingNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) { this.context = context; this.guardAnchor = guardAnchor; this.activeGuards = activeGuards; @@ -68,12 +69,19 @@ } @Override - public ValueNode createNullCheckGuard(ValueNode object) { - return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); + public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) { + if (object.objectStamp().nonNull()) { + // Short cut creation of null check guard if the object is known to be non-null. + return null; + } + GuardingNode guard = createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); + assert guardedNode.getGuard() == null; + guardedNode.setGuard(guard); + return guard; } @Override - public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) { + public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) { return createGuard(condition, deoptReason, action, false); } @@ -83,7 +91,7 @@ } @Override - public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { + public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { if (loweringType == LoweringType.AFTER_GUARDS) { throw new GraalInternalError("Cannot create guards in after-guard lowering"); } @@ -94,7 +102,7 @@ } } } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated)); + GuardNode newGuard = guardAnchor.asNode().graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated)); if (GraalOptions.OptEliminateGuards) { activeGuards.grow(); activeGuards.mark(newGuard); @@ -173,9 +181,9 @@ processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null); } - private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor) { + private void processBlock(Block block, NodeBitMap activeGuards, GuardingNode parentAnchor) { - FixedNode anchor = parentAnchor; + GuardingNode anchor = parentAnchor; if (anchor == null) { anchor = block.getBeginNode(); } @@ -196,13 +204,13 @@ } if (parentAnchor == null && GraalOptions.OptEliminateGuards) { - for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { + for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) { activeGuards.clear(guard); } } } - private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor) { + private void process(final Block b, final NodeBitMap activeGuards, final GuardingNode anchor) { final LoweringToolImpl loweringTool = new LoweringToolImpl(context, anchor, activeGuards, schedule.getCFG()); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -36,13 +36,14 @@ import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.tiers.*; /** * This class is a phase that looks for opportunities for tail duplication. The static method - * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail - * duplication from other places, e.g., inlining. + * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List, PhaseContext)} can also be used + * to drive tail duplication from other places, e.g., inlining. */ -public class TailDuplicationPhase extends Phase { +public class TailDuplicationPhase extends BasePhase { /* * Various metrics on the circumstances in which tail duplication was/wasn't performed. @@ -129,14 +130,14 @@ }; @Override - protected void run(StructuredGraph graph) { + protected void run(StructuredGraph graph, PhaseContext phaseContext) { NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); // A snapshot is taken here, so that new MergeNode instances aren't considered for tail // duplication. for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) { - tailDuplicate(merge, DEFAULT_DECISION, null); + tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext); } } } @@ -156,8 +157,9 @@ * size needs to match the merge's end count. Each entry can either be null or a * {@link PiNode}, and is used to replace {@link PiNode#object()} with the * {@link PiNode} in the duplicated branch that corresponds to the entry. + * @param phaseContext */ - public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { + public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements, PhaseContext phaseContext) { assert !(merge instanceof LoopBeginNode); assert replacements == null || replacements.size() == merge.forwardEndCount(); FixedNode fixed = merge; @@ -167,18 +169,18 @@ fixedCount++; } if (fixedCount > 1) { - if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) { + if (fixed instanceof AbstractEndNode && !(((AbstractEndNode) fixed).merge() instanceof LoopBeginNode)) { metricDuplicationEnd.increment(); if (decision.doTransform(merge, fixedCount)) { metricDuplicationEndPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); + new DuplicationOperation(merge, replacements).duplicate(phaseContext); return true; } } else if (merge.stateAfter() != null) { metricDuplicationOther.increment(); if (decision.doTransform(merge, fixedCount)) { metricDuplicationOtherPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); + new DuplicationOperation(merge, replacements).duplicate(phaseContext); return true; } } @@ -207,7 +209,7 @@ public DuplicationOperation(MergeNode merge, List replacements) { this.merge = merge; this.replacements = replacements; - this.graph = (StructuredGraph) merge.graph(); + this.graph = merge.graph(); } /** @@ -220,10 +222,14 @@ *
  • Determines the complete set of duplicated nodes.
  • *
  • Performs the actual duplication.
  • * + * + * @param phaseContext */ - private void duplicate() { + private void duplicate(PhaseContext phaseContext) { Debug.log("tail duplication at merge %s in %s", merge, graph.method()); + int startMark = graph.getMark(); + ValueAnchorNode anchor = addValueAnchor(); // determine the fixed nodes that should be duplicated (currently: all nodes up until @@ -240,18 +246,18 @@ fixed = ((FixedWithNextNode) fixed).next(); } - EndNode endAfter = createNewMerge(fixed, stateAfter); + AbstractEndNode endAfter = createNewMerge(fixed, stateAfter); MergeNode mergeAfter = endAfter.merge(); fixedNodes.add(endAfter); final HashSet duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); mergeAfter.clearEnds(); expandDuplicated(duplicatedNodes, mergeAfter); - List endSnapshot = merge.forwardEnds().snapshot(); + List endSnapshot = merge.forwardEnds().snapshot(); List phiSnapshot = merge.phis().snapshot(); int endIndex = 0; - for (final EndNode forwardEnd : merge.forwardEnds()) { + for (final AbstractEndNode forwardEnd : merge.forwardEnds()) { Map duplicates; if (replacements == null || replacements.get(endIndex) == null) { duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null); @@ -263,31 +269,26 @@ for (Map.Entry phi : bottomPhis.entrySet()) { phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey())); } - mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter)); + mergeAfter.addForwardEnd((AbstractEndNode) duplicates.get(endAfter)); // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding // EndNode FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor); ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate); // move dependencies on the ValueAnchorNode to the previous BeginNode - BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate); + AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(anchorDuplicate); anchorDuplicate.replaceAtUsages(prevBegin); // re-wire the phi duplicates to the correct input for (PhiNode phi : phiSnapshot) { PhiNode phiDuplicate = (PhiNode) duplicates.get(phi); - for (Node usage : phiDuplicate.usages()) { - if (usage instanceof ValueNode) { - ((ValueNode) usage).dependencies().add(prevBegin); - } - } phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd)); phiDuplicate.safeDelete(); } endIndex++; } GraphUtil.killCFG(merge); - for (EndNode forwardEnd : endSnapshot) { + for (AbstractEndNode forwardEnd : endSnapshot) { forwardEnd.safeDelete(); } for (PhiNode phi : phiSnapshot) { @@ -297,6 +298,7 @@ phi.setMerge(mergeAfter); } } + new CanonicalizerPhase(null, graph.getNewNodes(startMark)).apply(graph, phaseContext); Debug.dump(graph, "After tail duplication at %s", merge); } @@ -421,9 +423,9 @@ * @param stateAfterMerge The frame state that should be used for the merge. * @return The newly created end node. */ - private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { + private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { MergeNode newBottomMerge = graph.add(new MergeNode()); - EndNode newBottomEnd = graph.add(new EndNode()); + AbstractEndNode newBottomEnd = graph.add(new EndNode()); newBottomMerge.addForwardEnd(newBottomEnd); newBottomMerge.setStateAfter(stateAfterMerge); ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon May 13 17:11:31 2013 +0200 @@ -34,9 +34,13 @@ private static final boolean ____ = false; // Checkstyle: resume - public static int Threads = 4; + public static int Threads; + static { + Threads = Runtime.getRuntime().availableProcessors(); + } public static String CompilerConfiguration = "basic"; + public static String GraalRuntime = "basic"; // inlining settings public static boolean Inline = true; @@ -44,7 +48,8 @@ public static boolean Intrinsify = true; static boolean InlineMonomorphicCalls = true; static boolean InlinePolymorphicCalls = true; - static boolean InlineMegamorphicCalls = ____; + static boolean InlineMegamorphicCalls = true; + public static double MegamorphicInliningMinMethodProbability = 0.33; public static int MaximumDesiredSize = 5000; public static int MaximumRecursiveInlining = 1; public static float BoostInliningForEscapeAnalysis = 2f; @@ -103,6 +108,7 @@ public static int LoopMaxUnswitch = 3; public static int LoopUnswitchMaxIncrease = 50; public static int LoopUnswitchUncertaintyBoost = 5; + public static boolean UseLoopLimitChecks = true; // debugging settings public static boolean ZapStackOnMethodEntry = ____; @@ -219,6 +225,7 @@ public static boolean IntrinsifyUnsafeMethods = true; public static boolean IntrinsifyMathMethods = true; public static boolean IntrinsifyAESMethods = true; + public static boolean IntrinsifyReflectionMethods = true; public static boolean IntrinsifyInstalledCodeMethods = true; public static boolean IntrinsifyCallSiteTarget = true; /** diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Mon May 13 17:11:31 2013 +0200 @@ -34,7 +34,7 @@ private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts"); public static enum Optimization { - RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability + RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability, UseLoopLimitChecks } private final Set enabledOpts; @@ -47,6 +47,7 @@ addOptimization(method, DeoptimizationReason.TypeCheckedInliningViolated, Optimization.UseTypeCheckedInlining); addOptimization(method, DeoptimizationReason.OptimizedTypeCheckViolated, Optimization.UseTypeCheckHints); addOptimization(method, DeoptimizationReason.NotCompiledExceptionHandler, Optimization.UseExceptionProbability); + addOptimization(method, DeoptimizationReason.LoopLimitCheck, Optimization.UseLoopLimitChecks); } private void addOptimization(ResolvedJavaMethod method, DeoptimizationReason deoptReason, Optimization optimization) { @@ -109,6 +110,10 @@ return GraalOptions.UseExceptionProbabilityForOperations && enabledOpts.contains(Optimization.UseExceptionProbabilityForOperations); } + public boolean useLoopLimitChecks() { + return GraalOptions.UseLoopLimitChecks && enabledOpts.contains(Optimization.UseLoopLimitChecks); + } + public boolean lessOptimisticThan(OptimisticOptimizations other) { for (Optimization opt : Optimization.values()) { if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/VerifyPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/VerifyPhase.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,35 @@ +/* + * 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.phases; + +import com.oracle.graal.nodes.*; + +public abstract class VerifyPhase extends Phase { + + @Override + protected final void run(StructuredGraph graph) { + assert verify(graph); + } + + protected abstract boolean verify(StructuredGraph graph); +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Mon May 13 17:11:31 2013 +0200 @@ -70,7 +70,7 @@ if (scope.start instanceof LoopBeginNode) { assert scope.parent != null; double parentProbability = 0; - for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) { + for (AbstractEndNode end : ((LoopBeginNode) scope.start).forwardEnds()) { parentProbability += nodeProbabilities.get(end); } return parentProbability / scope.parent.minPathProbability; @@ -170,7 +170,7 @@ int pathBeginCount = pathBeginNodes.size(); for (Node sux : controlSplit.successors()) { - double probability = controlSplit.probability((BeginNode) sux); + double probability = controlSplit.probability((AbstractBeginNode) sux); if (probability > maxProbability) { maxProbability = probability; maxSux = sux; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Mon May 13 17:11:31 2013 +0200 @@ -76,11 +76,6 @@ } } - private static boolean isRelativeProbability(double prob) { - // 1.01 to allow for some rounding errors - return prob >= 0 && prob <= 1.01; - } - public static class LoopInfo { public final LoopBeginNode loopBegin; @@ -128,6 +123,7 @@ public LoopInfo loopInfo; public Probability(double probability, HashSet loops) { + assert probability >= 0.0; this.probability = probability; this.loops = new HashSet<>(4); if (loops != null) { @@ -171,7 +167,7 @@ } loops = intersection; mergeLoops.put(merge, new HashSet<>(intersection)); - assert isRelativeProbability(probability) : probability; + probability = Math.max(0.0, probability); } return true; } @@ -205,7 +201,7 @@ } @Override - public void afterSplit(BeginNode node) { + public void afterSplit(AbstractBeginNode node) { assert node.predecessor() != null; Node pred = node.predecessor(); if (pred instanceof Invoke) { @@ -216,7 +212,10 @@ } else { assert pred instanceof ControlSplitNode; ControlSplitNode x = (ControlSplitNode) pred; - probability *= x.probability(node); + double nodeProbability = x.probability(node); + assert nodeProbability >= 0.0 : "Node " + x + " provided negative probability for begin " + node + ": " + nodeProbability; + probability *= nodeProbability; + assert probability >= 0.0; } } } @@ -272,7 +271,7 @@ } @Override - public void afterSplit(BeginNode node) { + public void afterSplit(AbstractBeginNode node) { // nothing to do... } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java Mon May 13 17:11:31 2013 +0200 @@ -36,5 +36,5 @@ void loopEnds(LoopBeginNode loopBegin, List loopEndStates); - void afterSplit(BeginNode node); + void afterSplit(AbstractBeginNode node); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Mon May 13 17:11:31 2013 +0200 @@ -43,7 +43,7 @@ public abstract class PostOrderNodeIterator> { private final NodeBitMap visitedEnds; - private final Deque nodeQueue; + private final Deque nodeQueue; private final IdentityHashMap nodeStates; private final FixedNode start; @@ -109,13 +109,13 @@ for (Node node : successors) { if (node != null) { nodeStates.put((FixedNode) node.predecessor(), state); - nodeQueue.addFirst((BeginNode) node); + nodeQueue.addFirst((AbstractBeginNode) node); } } } else { for (Node node : x.successors()) { if (node != null) { - nodeQueue.addFirst((BeginNode) node); + nodeQueue.addFirst((AbstractBeginNode) node); } } } @@ -124,7 +124,7 @@ private FixedNode nextQueuedNode() { int maxIterations = nodeQueue.size(); while (maxIterations-- > 0) { - BeginNode node = nodeQueue.removeFirst(); + AbstractBeginNode node = nodeQueue.removeFirst(); if (node instanceof MergeNode) { MergeNode merge = (MergeNode) node; state = nodeStates.get(merge.forwardEndAt(0)).clone(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Mon May 13 17:11:31 2013 +0200 @@ -37,7 +37,7 @@ public abstract static class BlockIteratorClosure { - protected abstract void processBlock(Block block, StateT currentState); + protected abstract StateT processBlock(Block block, StateT currentState); protected abstract StateT merge(Block merge, List states); @@ -62,8 +62,8 @@ } for (Block loopExit : loop.exits) { assert loopExit.getPredecessorCount() == 1; + assert blockEndStates.containsKey(loopExit.getBeginNode()); StateT exitState = blockEndStates.get(loopExit.getBeginNode()); - assert exitState != null; // make sure all exit states are unique objects info.exitStates.add(closure.cloneState(exitState)); } @@ -82,7 +82,7 @@ while (true) { if (boundary == null || boundary.contains(current)) { - closure.processBlock(current, state); + state = closure.processBlock(current, state); if (current.getSuccessors().isEmpty()) { // nothing to do... @@ -115,16 +115,16 @@ current = successor; continue; } else { - if (current.getEndNode() instanceof EndNode) { + if (current.getEndNode() instanceof AbstractEndNode) { assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode(); - EndNode end = (EndNode) current.getEndNode(); + AbstractEndNode end = (AbstractEndNode) current.getEndNode(); // add the end node and see if the merge is ready for processing assert !states.containsKey(end); states.put(end, state); MergeNode merge = end.merge(); boolean endsVisited = true; - for (EndNode forwardEnd : merge.forwardEnds()) { + for (AbstractEndNode forwardEnd : merge.forwardEnds()) { if (!states.containsKey(forwardEnd)) { endsVisited = false; break; @@ -156,18 +156,18 @@ } else { current = blockQueue.removeFirst(); if (current.getPredecessors().size() == 1) { + assert states.containsKey(current.getBeginNode()); state = states.get(current.getBeginNode()); } else { assert current.getPredecessors().size() > 1; MergeNode merge = (MergeNode) current.getBeginNode(); ArrayList mergedStates = new ArrayList<>(merge.forwardEndCount()); for (Block predecessor : current.getPredecessors()) { - EndNode end = (EndNode) predecessor.getEndNode(); + AbstractEndNode end = (AbstractEndNode) predecessor.getEndNode(); mergedStates.add(states.get(end)); } state = closure.merge(current, mergedStates); } - assert state != null; } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Mon May 13 17:11:31 2013 +0200 @@ -37,11 +37,11 @@ public abstract static class NodeIteratorClosure { - protected abstract void processNode(FixedNode node, StateT currentState); + protected abstract StateT processNode(FixedNode node, StateT currentState); protected abstract StateT merge(MergeNode merge, List states); - protected abstract StateT afterSplit(BeginNode node, StateT oldState); + protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState); protected abstract Map processLoop(LoopBeginNode loop, StateT initialState); } @@ -70,7 +70,7 @@ } public static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState, Set boundary) { - Deque nodeQueue = new ArrayDeque<>(); + Deque nodeQueue = new ArrayDeque<>(); IdentityHashMap blockEndStates = new IdentityHashMap<>(); StateT state = initialState; @@ -82,13 +82,13 @@ current = null; } else { FixedNode next = ((FixedWithNextNode) current).next(); - closure.processNode(current, state); + state = closure.processNode(current, state); current = next; } } if (current != null) { - closure.processNode(current, state); + state = closure.processNode(current, state); NodeClassIterator successors = current.successors().iterator(); if (!successors.hasNext()) { @@ -107,7 +107,7 @@ assert !blockEndStates.containsKey(current); blockEndStates.put(current, state); boolean endsVisited = true; - for (EndNode forwardEnd : merge.forwardEnds()) { + for (AbstractEndNode forwardEnd : merge.forwardEnds()) { if (!blockEndStates.containsKey(forwardEnd)) { endsVisited = false; break; @@ -116,7 +116,7 @@ if (endsVisited) { ArrayList states = new ArrayList<>(merge.forwardEndCount()); for (int i = 0; i < merge.forwardEndCount(); i++) { - EndNode forwardEnd = merge.forwardEndAt(i); + AbstractEndNode forwardEnd = merge.forwardEndAt(i); assert blockEndStates.containsKey(forwardEnd); StateT other = blockEndStates.get(forwardEnd); states.add(other); @@ -134,11 +134,11 @@ continue; } else { while (successors.hasNext()) { - BeginNode successor = (BeginNode) successors.next(); + AbstractBeginNode successor = (AbstractBeginNode) successors.next(); blockEndStates.put(successor, closure.afterSplit(successor, state)); nodeQueue.add(successor); } - state = closure.afterSplit((BeginNode) firstSuccessor, state); + state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state); current = firstSuccessor; continue; } @@ -151,7 +151,7 @@ } else { current = nodeQueue.removeFirst(); state = blockEndStates.get(current); - assert !(current instanceof MergeNode) && current instanceof BeginNode; + assert !(current instanceof MergeNode) && current instanceof AbstractBeginNode; } } while (true); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java Mon May 13 17:11:31 2013 +0200 @@ -141,7 +141,7 @@ return result; } - private void queueMerge(EndNode end) { + private void queueMerge(AbstractEndNode end) { MergeNode merge = end.merge(); if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) { queue(merge); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon May 13 17:11:31 2013 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; @@ -83,22 +84,23 @@ private class MemoryScheduleClosure extends BlockIteratorClosure> { @Override - protected void processBlock(Block block, HashSet currentState) { + protected HashSet processBlock(Block block, HashSet currentState) { for (Node node : getBlockToNodesMap().get(block)) { if (node instanceof FloatingReadNode) { currentState.add((FloatingReadNode) node); } else if (node instanceof MemoryCheckpoint) { - for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) { + for (LocationIdentity identity : ((MemoryCheckpoint) node).getLocationIdentities()) { for (Iterator iter = currentState.iterator(); iter.hasNext();) { FloatingReadNode read = iter.next(); FixedNode fixed = (FixedNode) node; - if (identity == LocationNode.ANY_LOCATION || read.location().locationIdentity() == identity) { + if (identity == LocationNode.ANY_LOCATION || read.location().getLocationIdentity() == identity) { addPhantomReference(read, fixed); } } } } } + return currentState; } public void addPhantomReference(FloatingReadNode read, FixedNode fixed) { @@ -171,7 +173,7 @@ @Override protected void run(StructuredGraph graph) { - cfg = ControlFlowGraph.compute(graph, true, true, true, false); + cfg = ControlFlowGraph.compute(graph, true, true, true, true); earliestCache = graph.createNodeMap(); blockToNodesMap = new BlockMap<>(cfg); @@ -652,7 +654,7 @@ } } - if (instruction instanceof BeginNode) { + if (instruction instanceof AbstractBeginNode) { ArrayList proxies = (instruction instanceof LoopExitNode) ? new ArrayList() : null; for (ScheduledNode inBlock : blockToNodesMap.get(b)) { if (!visited.isMarked(inBlock)) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java Mon May 13 17:11:31 2013 +0200 @@ -25,17 +25,24 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; public class MidTierContext extends PhaseContext { private final TargetDescription target; + private final OptimisticOptimizations optimisticOpts; - public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) { + public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target, OptimisticOptimizations optimisticOpts) { super(runtime, assumptions, replacements); this.target = target; + this.optimisticOpts = optimisticOpts; } public TargetDescription getTarget() { return target; } + + public OptimisticOptimizations getOptimisticOptimizations() { + return optimisticOpts; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Mon May 13 17:11:31 2013 +0200 @@ -39,13 +39,7 @@ NodeBitMap visited = graph.createNodeBitMap(); - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - result.visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - result.visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { + for (ControlSinkNode node : graph.getNodes(ControlSinkNode.class)) { result.visitForward(visited, node); } return result; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyValueUsage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyValueUsage.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,61 @@ +/* + * 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.phases.verify; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; + +public class VerifyValueUsage extends VerifyPhase { + + private MetaAccessProvider runtime; + + public VerifyValueUsage(MetaAccessProvider runtime) { + this.runtime = runtime; + } + + private boolean checkType(ValueNode node) { + if (node.stamp() instanceof ObjectStamp) { + ResolvedJavaType valueType = runtime.lookupJavaType(Value.class); + ResolvedJavaType nodeType = node.objectStamp().type(); + + if (valueType.isAssignableFrom(nodeType)) { + return true; + } + } + return false; + } + + @Override + protected boolean verify(StructuredGraph graph) { + for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) { + String desc = "VerifyValueUsage: " + cn.x() + " or " + cn.y() + " in " + graph.method() + " uses object identity. Should use equals() instead."; + if (!graph.method().toString().endsWith("equals(Object)>")) { + assert !((checkType(cn.x()) && !(cn.y() instanceof ConstantNode)) || (checkType(cn.y()) && !(cn.x() instanceof ConstantNode))) : desc; + } + } + return true; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Mon May 13 17:11:31 2013 +0200 @@ -162,7 +162,7 @@ PhiNode phi = (PhiNode) node; assert nodeBlock.getBeginNode() == phi.merge(); for (Block pred : nodeBlock.getPredecessors()) { - schedule(phi.valueAt((EndNode) pred.getEndNode()), pred); + schedule(phi.valueAt((AbstractEndNode) pred.getEndNode()), pred); } } else { @@ -446,9 +446,10 @@ @Override protected void doState(LIRFrameState state) { if (state.hasDebugInfo()) { - stateString.append(debugInfoToString(state.debugInfo().getBytecodePosition(), state.debugInfo().getRegisterRefMap(), state.debugInfo().getFrameRefMap(), target.arch)); + DebugInfo di = state.debugInfo(); + stateString.append(debugInfoToString(di.getBytecodePosition(), di.getRegisterRefMap(), di.getFrameRefMap(), di.getCalleeSaveInfo(), target.arch)); } else { - stateString.append(debugInfoToString(state.topFrame, null, null, target.arch)); + stateString.append(debugInfoToString(state.topFrame, null, null, null, target.arch)); } } }); @@ -470,7 +471,7 @@ return "-"; } String prefix; - if (node instanceof BeginNode && lir == null) { + if (node instanceof AbstractBeginNode && lir == null) { prefix = "B"; } else if (node instanceof ValueNode) { ValueNode value = (ValueNode) node; diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Mon May 13 17:11:31 2013 +0200 @@ -45,7 +45,7 @@ private CFGPrinter cfgPrinter; private File cfgFile; - private ResolvedJavaMethod curMethod; + private JavaMethod curMethod; private List curDecorators = Collections.emptyList(); @Override @@ -64,17 +64,18 @@ * and decorator pair. */ private boolean checkMethodScope() { - ResolvedJavaMethod method = null; + JavaMethod method = null; ArrayList decorators = new ArrayList<>(); for (Object o : Debug.context()) { - if (o instanceof ResolvedJavaMethod) { - method = (ResolvedJavaMethod) o; + if (o instanceof JavaMethod) { + method = (JavaMethod) o; decorators.clear(); } else if (o instanceof StructuredGraph) { StructuredGraph graph = (StructuredGraph) o; - assert graph != null && graph.method() != null : "cannot find method context for CFG dump"; - method = graph.method(); - decorators.clear(); + if (graph.method() != null) { + method = graph.method(); + decorators.clear(); + } } else if (o instanceof DebugDumpScope) { DebugDumpScope debugDumpScope = (DebugDumpScope) o; if (debugDumpScope.decorator) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Mon May 13 17:11:31 2013 +0200 @@ -114,7 +114,7 @@ /** * Formats given debug info as a multi line string. */ - protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, Architecture arch) { + protected String debugInfoToString(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, RegisterSaveLayout calleeSaveInfo, Architecture arch) { StringBuilder sb = new StringBuilder(); if (registerRefMap != null) { @@ -128,8 +128,16 @@ if (frameRefMap != null) { sb.append("frame-ref-map:"); - for (int reg = frameRefMap.nextSetBit(0); reg >= 0; reg = frameRefMap.nextSetBit(reg + 1)) { - sb.append(' ').append("s").append(reg); + for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + 1)) { + sb.append(' ').append("s").append(slot); + } + sb.append("\n"); + } + + if (calleeSaveInfo != null) { + sb.append("callee-save-info:"); + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(" " + e.getKey() + " -> s" + e.getValue()); } sb.append("\n"); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Mon May 13 17:11:31 2013 +0200 @@ -30,6 +30,7 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.phases.*; @@ -180,10 +181,18 @@ private static List getInlineContext() { List result = new ArrayList<>(); + Object last = null; for (Object o : Debug.context()) { - if (o instanceof ResolvedJavaMethod) { - ResolvedJavaMethod method = (ResolvedJavaMethod) o; - result.add(MetaUtil.format("%H::%n(%p)", method)); + JavaMethod method = GraalDebugConfig.asJavaMethod(o); + if (method != null) { + if (last != method) { + result.add(MetaUtil.format("%H::%n(%p)", method)); + } else { + // This prevents multiple adjacent method context objects for the same method + // from resulting in multiple IGV tree levels. This works on the + // assumption that real inlining debug scopes will have a graph + // context object between the inliner and inlinee context objects. + } } else if (o instanceof DebugDumpScope) { DebugDumpScope debugDumpScope = (DebugDumpScope) o; if (debugDumpScope.decorator && !result.isEmpty()) { @@ -192,6 +201,7 @@ result.add(debugDumpScope.name); } } + last = o; } if (result.isEmpty()) { result.add("Top Scope"); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Mon May 13 17:11:31 2013 +0200 @@ -165,9 +165,9 @@ printProperty(bit, "true"); } } - if (node.getClass() == BeginNode.class) { + if (node.getClass() == AbstractBeginNode.class) { printProperty("shortName", "B"); - } else if (node.getClass() == EndNode.class) { + } else if (node.getClass() == AbstractEndNode.class) { printProperty("shortName", "E"); } if (node.predecessor() != null) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java --- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java Mon May 13 17:11:31 2013 +0200 @@ -23,18 +23,21 @@ package com.oracle.graal.ptx; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.code.Register.RegisterFlag.*; import java.nio.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Register.*; +import com.oracle.graal.api.code.Register.RegisterCategory; +import com.oracle.graal.api.meta.*; /** * Represents the PTX architecture. */ public class PTX extends Architecture { + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + public static final RegisterCategory FPU = new RegisterCategory("FPU"); + // @formatter:off /* @@ -49,23 +52,23 @@ */ // General purpose registers - public static final Register r0 = new Register(0, 0, 8, "r0", CPU, RegisterFlag.Byte); - public static final Register r1 = new Register(1, 1, 8, "r1", CPU, RegisterFlag.Byte); - public static final Register r2 = new Register(2, 2, 8, "r2", CPU, RegisterFlag.Byte); - public static final Register r3 = new Register(3, 3, 8, "r3", CPU, RegisterFlag.Byte); - public static final Register r4 = new Register(4, 4, 8, "r4", CPU, RegisterFlag.Byte); - public static final Register r5 = new Register(5, 5, 8, "r5", CPU, RegisterFlag.Byte); - public static final Register r6 = new Register(6, 6, 8, "r6", CPU, RegisterFlag.Byte); - public static final Register r7 = new Register(7, 7, 8, "r7", CPU, RegisterFlag.Byte); + public static final Register r0 = new Register(0, 0, "r0", CPU); + public static final Register r1 = new Register(1, 1, "r1", CPU); + public static final Register r2 = new Register(2, 2, "r2", CPU); + public static final Register r3 = new Register(3, 3, "r3", CPU); + public static final Register r4 = new Register(4, 4, "r4", CPU); + public static final Register r5 = new Register(5, 5, "r5", CPU); + public static final Register r6 = new Register(6, 6, "r6", CPU); + public static final Register r7 = new Register(7, 7, "r7", CPU); - public static final Register r8 = new Register(8, 8, 8, "r8", CPU, RegisterFlag.Byte); - public static final Register r9 = new Register(9, 9, 8, "r9", CPU, RegisterFlag.Byte); - public static final Register r10 = new Register(10, 10, 8, "r10", CPU, RegisterFlag.Byte); - public static final Register r11 = new Register(11, 11, 8, "r11", CPU, RegisterFlag.Byte); - public static final Register r12 = new Register(12, 12, 8, "r12", CPU, RegisterFlag.Byte); - public static final Register r13 = new Register(13, 13, 8, "r13", CPU, RegisterFlag.Byte); - public static final Register r14 = new Register(14, 14, 8, "r14", CPU, RegisterFlag.Byte); - public static final Register r15 = new Register(15, 15, 8, "r15", CPU, RegisterFlag.Byte); + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); public static final Register[] gprRegisters = { r0, r1, r2, r3, r4, r5, r6, r7, @@ -73,23 +76,23 @@ }; // Floating point registers - public static final Register f0 = new Register(16, 0, 8, "f0", FPU); - public static final Register f1 = new Register(17, 1, 8, "f1", FPU); - public static final Register f2 = new Register(18, 2, 8, "f2", FPU); - public static final Register f3 = new Register(19, 3, 8, "f3", FPU); - public static final Register f4 = new Register(20, 4, 8, "f4", FPU); - public static final Register f5 = new Register(21, 5, 8, "f5", FPU); - public static final Register f6 = new Register(22, 6, 8, "f6", FPU); - public static final Register f7 = new Register(23, 7, 8, "f7", FPU); + public static final Register f0 = new Register(16, 0, "f0", FPU); + public static final Register f1 = new Register(17, 1, "f1", FPU); + public static final Register f2 = new Register(18, 2, "f2", FPU); + public static final Register f3 = new Register(19, 3, "f3", FPU); + public static final Register f4 = new Register(20, 4, "f4", FPU); + public static final Register f5 = new Register(21, 5, "f5", FPU); + public static final Register f6 = new Register(22, 6, "f6", FPU); + public static final Register f7 = new Register(23, 7, "f7", FPU); - public static final Register f8 = new Register(24, 8, 8, "f8", FPU); - public static final Register f9 = new Register(25, 9, 8, "f9", FPU); - public static final Register f10 = new Register(26, 10, 8, "f10", FPU); - public static final Register f11 = new Register(27, 11, 8, "f11", FPU); - public static final Register f12 = new Register(28, 12, 8, "f12", FPU); - public static final Register f13 = new Register(29, 13, 8, "f13", FPU); - public static final Register f14 = new Register(30, 14, 8, "f14", FPU); - public static final Register f15 = new Register(31, 15, 8, "f15", FPU); + public static final Register f8 = new Register(24, 8, "f8", FPU); + public static final Register f9 = new Register(25, 9, "f9", FPU); + public static final Register f10 = new Register(26, 10, "f10", FPU); + public static final Register f11 = new Register(27, 11, "f11", FPU); + public static final Register f12 = new Register(28, 12, "f12", FPU); + public static final Register f13 = new Register(29, 13, "f13", FPU); + public static final Register f14 = new Register(30, 14, "f14", FPU); + public static final Register f15 = new Register(31, 15, "f15", FPU); public static final Register[] fpuRegisters = { f0, f1, f2, f3, f4, f5, f6, f7, @@ -116,4 +119,44 @@ 8); } // @formatter:on + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + if (!(platformKind instanceof Kind)) { + return false; + } + + Kind kind = (Kind) platformKind; + if (category == CPU) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return true; + } + } else if (category == FPU) { + switch (kind) { + case Float: + case Double: + return true; + } + } + + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category == CPU) { + return Kind.Long; + } else if (category == FPU) { + return Kind.Double; + } else { + return Kind.Illegal; + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -28,6 +28,7 @@ import java.util.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -148,7 +149,7 @@ private final EnumMap snippets; - public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { super(runtime, replacements, target); snippets = new EnumMap<>(Op.class); @@ -164,7 +165,7 @@ return; } - StructuredGraph graph = (StructuredGraph) convert.graph(); + StructuredGraph graph = convert.graph(); // Insert a unique placeholder node in place of the Convert node so that the // Convert node can be used as an input to the snippet. All usage of the diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Mon May 13 17:11:31 2013 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.replacements.test; - import com.oracle.graal.api.meta.*; import com.oracle.graal.test.*; import com.oracle.graal.nodes.*; @@ -37,7 +36,7 @@ protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile, false)); graph.replaceFixedWithFixed(ccn, ccnNew); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java Mon May 13 17:11:31 2013 +0200 @@ -64,6 +64,7 @@ } test("test1Snippet", "a string"); + test("test1Snippet", (String) null); } public static String test1Snippet(String message) { @@ -76,4 +77,51 @@ } return null; } + + private static void raiseException(String m1, String m2, String m3, String m4, String m5) { + throw new RuntimeException(m1 + m2 + m3 + m4 + m5); + } + + @Test + public void test2() { + // Ensure the profile shows a hot exception + for (int i = 0; i < 10000; i++) { + test2Snippet("m1", "m2", "m3", "m4", "m5"); + test2Snippet(null, "m2", "m3", "m4", "m5"); + } + + test("test2Snippet", "m1", "m2", "m3", "m4", "m5"); + test("test2Snippet", null, "m2", "m3", "m4", "m5"); + } + + public static String test2Snippet(String m1, String m2, String m3, String m4, String m5) { + if (m1 != null) { + try { + raiseException(m1, m2, m3, m4, m5); + } catch (Exception e) { + return m5 + m4 + m3 + m2 + m1; + } + } + return m4 + m3; + } + + @Test + public void test3() { + // Ensure the profile shows a hot exception + for (int i = 0; i < 10000; i++) { + test3Snippet("object1", "object2"); + test3Snippet(null, "object2"); + } + + test("test3Snippet", (Object) null, "object2"); + test("test3Snippet", "object1", "object2"); + } + + public static String test3Snippet(Object o, Object o2) { + try { + return o.toString(); + } catch (NullPointerException e) { + return String.valueOf(o2); + } + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DeoptimizeOnExceptionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DeoptimizeOnExceptionTest.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,59 @@ +/* + * 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.test; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests that deoptimization upon exception handling works. + */ +public class DeoptimizeOnExceptionTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + private static void raiseException(String m1, String m2, String m3, String m4, String m5) { + throw new RuntimeException(m1 + m2 + m3 + m4 + m5); + } + + @Test + public void test1() { + test("test1Snippet", "m1", "m2", "m3", "m4", "m5"); + } + + // no local exception handler - will deopt + public static String test1Snippet(String m1, String m2, String m3, String m4, String m5) { + if (m1 != null) { + raiseException(m1, m2, m3, m4, m5); + } + return m1 + m2 + m3 + m4 + m5; + } +} diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon May 13 17:11:31 2013 +0200 @@ -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.extended.LocationNode.LocationIdentity; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.word.*; @@ -42,7 +43,7 @@ */ public class PointerTest extends GraalCompilerTest implements Snippets { - private static final Object ID = new Object(); + private static final LocationIdentity ID = LocationNode.createLocation("ID"); private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; private final TargetDescription target; private final ReplacementsImpl installer; @@ -102,7 +103,7 @@ } } - private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) { ReadNode read = (ReadNode) graph.start().next(); Assert.assertEquals(kind.getStackKind(), read.kind()); @@ -112,22 +113,22 @@ IndexedLocationNode location = (IndexedLocationNode) read.location(); Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); + Assert.assertEquals(locationIdentity, location.getLocationIdentity()); + Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); + ConvertNode convert = (ConvertNode) location.getIndex(); Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); Assert.assertEquals(graph.getLocal(1), convert.value()); } else { - Assert.assertEquals(graph.getLocal(1), location.index()); + Assert.assertEquals(graph.getLocal(1), location.getIndex()); } ReturnNode ret = (ReturnNode) read.next(); Assert.assertEquals(read, ret.result()); } - private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) { WriteNode write = (WriteNode) graph.start().next(); Assert.assertEquals(graph.getLocal(2), write.value()); Assert.assertEquals(Kind.Void, write.kind()); @@ -139,15 +140,15 @@ IndexedLocationNode location = (IndexedLocationNode) write.location(); Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); + Assert.assertEquals(locationIdentity, location.getLocationIdentity()); + Assert.assertEquals(1, location.getIndexScaling()); if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); + ConvertNode convert = (ConvertNode) location.getIndex(); Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); Assert.assertEquals(graph.getLocal(1), convert.value()); } else { - Assert.assertEquals(graph.getLocal(1), location.index()); + Assert.assertEquals(graph.getLocal(1), location.getIndex()); } AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnwindExceptionToCallerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnwindExceptionToCallerTest.java Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,47 @@ +/* + * 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.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; + +/** + * Tests exception throwing from Graal compiled code. + */ +public class UnwindExceptionToCallerTest extends GraalCompilerTest { + + @Test + public void test1() { + NullPointerException npe = new NullPointerException(); + test("test1Snippet", "a string", npe); + test("test1Snippet", (String) null, npe); + } + + public static String test1Snippet(String message, NullPointerException npe) { + if (message == null) { + throw npe; + } + return message; + } +} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Mon May 13 17:11:31 2013 +0200 @@ -205,7 +205,7 @@ private final EnumMap boxSnippets = new EnumMap<>(Kind.class); private final EnumMap unboxSnippets = new EnumMap<>(Kind.class); - public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { super(runtime, replacements, target); for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Char, Kind.Double, Kind.Float, Kind.Int, Kind.Long, Kind.Short}) { boxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "ValueOf")); @@ -216,7 +216,7 @@ public void lower(BoxNode box) { FloatingNode canonical = canonicalizeBoxing(box, runtime); if (canonical != null) { - ((StructuredGraph) box.graph()).replaceFixedWithFloating(box, canonical); + box.graph().replaceFixedWithFloating(box, canonical); } else { Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind())); args.add("value", box.getValue()); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Mon May 13 17:11:31 2013 +0200 @@ -97,8 +97,8 @@ */ protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { InstanceOfUsageReplacer replacer; - if (usage instanceof IfNode) { - replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage); + if (usage instanceof IfNode || usage instanceof FixedGuardNode) { + replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (FixedNode) usage); } else { assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; ConditionalNode c = (ConditionalNode) usage; @@ -193,9 +193,9 @@ */ public static class IfUsageReplacer extends InstanceOfUsageReplacer { - private final IfNode usage; + private final FixedNode usage; - public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage) { + public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, FixedNode usage) { super(instantiation, instanceOf, trueValue, falseValue); this.usage = usage; } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.replacements; +import static com.oracle.graal.api.meta.MetaUtil.*; + import java.lang.reflect.*; import java.util.*; @@ -178,7 +180,8 @@ } else { result = runtime.lookupJavaType(intrinsic.value()); } - assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result); + assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result) : "Node intrinsic class " + toJavaName(result, false) + " derived from @" + NodeIntrinsic.class.getSimpleName() + + " annotation on " + format("%H.%n(%p)", target) + " is not a subclass of " + ValueNode.class; return result; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Mon May 13 17:11:31 2013 +0200 @@ -57,7 +57,7 @@ } private static void error(MethodCallTargetNode n, String failedAction) throws GraalInternalError { - String context = MetaUtil.format("%H.%n", ((StructuredGraph) n.graph()).method()); + String context = MetaUtil.format("%H.%n", n.graph().method()); String target = n.invoke().callTarget().targetName(); throw new GraalInternalError(failedAction + " of call to '" + target + "' in '" + context + "' failed, most likely due to a parameter annotated with @" + ConstantNodeParameter.class.getSimpleName() + " not being resolvable to a constant during compilation"); diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon May 13 17:11:31 2013 +0200 @@ -282,6 +282,7 @@ if (!SnippetTemplate.hasConstantParameter(method)) { NodeIntrinsificationVerificationPhase.verify(graph); } + new ConvertDeoptimizeToGuardPhase().apply(graph); if (original == null) { new SnippetFrameStateCleanupPhase().apply(graph); @@ -295,7 +296,14 @@ private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { StructuredGraph graph = graphCache.get(methodToParse); if (graph == null) { - graphCache.putIfAbsent(methodToParse, buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy)); + StructuredGraph newGraph = Debug.scope("ParseGraph", new Object[]{methodToParse}, new Callable() { + + public StructuredGraph call() throws Exception { + return buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy); + } + }); + + graphCache.putIfAbsent(methodToParse, newGraph); graph = graphCache.get(methodToParse); assert graph != null; } @@ -311,9 +319,11 @@ GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); graphBuilder.apply(graph); - Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName()); - new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); + } return graph; } @@ -360,12 +370,18 @@ afterInline(graph, originalGraph); substituteCallsOriginal = true; } else { - if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, methodToParse)) { + StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee); + if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && + (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) { StructuredGraph targetGraph; - StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee); if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { targetGraph = intrinsicGraph; } else { + if (callee.getName().startsWith("$jacoco")) { + throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + format("%H.%n(%p)", callee) + " from " + format("%H.%n(%p)", methodToParse) + + " while preparing replacement " + format("%H.%n(%p)", method) + ". Placing \"//JaCoCo Exclude\" anywhere in " + + methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); + } targetGraph = parseGraph(callee, policy); } InliningUtil.inline(callTarget.invoke(), targetGraph, true); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java Mon May 13 17:11:31 2013 +0200 @@ -45,33 +45,24 @@ @Override protected void run(StructuredGraph graph) { - ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); - } - - private static class CleanupState { - - public boolean containsFrameState; - - public CleanupState(boolean containsFrameState) { - this.containsFrameState = containsFrameState; - } + ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), false, null); } /** * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid * frame states, so that they can be marked with an invalid frame state. */ - private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { + private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { @Override - protected void processNode(FixedNode node, CleanupState currentState) { + protected Boolean processNode(FixedNode node, Boolean currentState) { if (node instanceof StateSplit) { StateSplit stateSplit = (StateSplit) node; FrameState frameState = stateSplit.stateAfter(); if (frameState != null) { if (stateSplit.hasSideEffect()) { - currentState.containsFrameState = true; stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + return true; } else { stateSplit.setStateAfter(null); } @@ -80,36 +71,37 @@ } } } + return currentState; } @Override - protected CleanupState merge(MergeNode merge, List states) { - for (CleanupState state : states) { - if (state.containsFrameState) { - return new CleanupState(true); + protected Boolean merge(MergeNode merge, List states) { + for (boolean state : states) { + if (state) { + return true; } } - return new CleanupState(false); + return false; } @Override - protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { - return new CleanupState(oldState.containsFrameState); + protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { + return oldState; } @Override - protected Map processLoop(LoopBeginNode loop, CleanupState initialState) { - LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); + protected Map processLoop(LoopBeginNode loop, Boolean initialState) { + LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, false); boolean containsFrameState = false; - for (CleanupState state : info.endStates.values()) { - containsFrameState |= state.containsFrameState; + for (Boolean state : info.endStates.values()) { + containsFrameState |= state; } if (containsFrameState) { loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); } - if (containsFrameState || initialState.containsFrameState) { - for (CleanupState state : info.exitStates.values()) { - state.containsFrameState = true; + if (containsFrameState || initialState) { + for (Map.Entry entry : info.exitStates.entrySet()) { + entry.setValue(true); } } return info.exitStates; diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon May 13 17:11:31 2013 +0200 @@ -116,6 +116,10 @@ public boolean isVarargsParameter(int paramIdx) { return varargsParameters[paramIdx]; } + + public String getParameterName(int paramIdx) { + return names[paramIdx]; + } } /** @@ -283,16 +287,20 @@ this.templates = new ConcurrentHashMap<>(); } + /** + * Finds the method in {@code declaringClass} annotated with {@link Snippet} named + * {@code methodName}. If {@code methodName} is null, then there must be exactly one snippet + * method in {@code declaringClass}. + */ protected SnippetInfo snippet(Class declaringClass, String methodName) { Method found = null; for (Method method : declaringClass.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null && method.getName().equals(methodName)) { - assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass; + if (method.getAnnotation(Snippet.class) != null && (methodName == null || method.getName().equals(methodName))) { + assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName); found = method; } } - assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass; - + assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + (methodName == null ? "" : " named " + methodName); return new SnippetInfo(runtime.lookupJavaMethod(found)); } @@ -432,7 +440,7 @@ if (loopBegin != null) { LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); int mark = snippetCopy.getMark(); - LoopTransformations.fullUnroll(loop, runtime, null); + LoopTransformations.fullUnroll(loop, runtime, replacements.getAssumptions()); new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), mark, null).apply(snippetCopy); } FixedNode explodeLoopNext = explodeLoop.next(); @@ -680,7 +688,7 @@ StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + StructuredGraph replaceeGraph = replacee.graph(); IdentityHashMap replacements = bind(replaceeGraph, runtime, args); Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); @@ -756,7 +764,7 @@ StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); StartNode entryPointNode = snippet.start(); FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + StructuredGraph replaceeGraph = replacee.graph(); IdentityHashMap replacements = bind(replaceeGraph, runtime, args); Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Mon May 13 17:11:31 2013 +0200 @@ -43,8 +43,8 @@ public static final double FAST_PATH_PROBABILITY = 0.99; public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; - public static final double VERY_FAST_DEOPT_PATH_PROBABILITY = 0.999; - public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_DEOPT_PATH_PROBABILITY; + public static final double VERY_FAST_PATH_PROBABILITY = 0.999; + public static final double VERY_SLOW_PATH_PROBABILITY = 1 - VERY_FAST_PATH_PROBABILITY; @Input private ValueNode probability; @Input private ValueNode condition; diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Mon May 13 17:11:31 2013 +0200 @@ -62,9 +62,8 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - StructuredGraph graph = (StructuredGraph) this.graph(); - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); - WriteNode write = graph.add(new WriteNode(object, value, location, WriteBarrierType.NONE)); - graph.replaceFixedWithFixed(this, write); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph(), 1); + WriteNode write = graph().add(new WriteNode(object, value, location, WriteBarrierType.NONE)); + graph().replaceFixedWithFixed(this, write); } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon May 13 17:11:31 2013 +0200 @@ -80,7 +80,7 @@ private InvokeNode replaceWithInvoke() { InvokeNode invoke = createInvoke(); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); + graph().replaceFixedWithFixed(this, invoke); return invoke; } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java --- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java Mon May 13 17:11:31 2013 +0200 @@ -27,6 +27,8 @@ import java.nio.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Register.RegisterCategory; +import com.oracle.graal.api.meta.*; /** * Represents the SPARC architecture. @@ -39,4 +41,16 @@ super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, null, LOAD_STORE | STORE_STORE, 1, 0, 8); // SPARC: Fix architecture parameters. } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind kind) { + // TODO Auto-generated method stub + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + // TODO Auto-generated method stub + return null; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.virtual.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; - -@NodeInfo(nameTemplate = "MaterializeStore#{p#target/s}") -public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable, Virtualizable { - - @Input private ValueNode object; - @Input private ValueNode value; - private final Object target; - - public ValueNode object() { - return object; - } - - public ValueNode value() { - return value; - } - - public ResolvedJavaField targetField() { - return (ResolvedJavaField) target; - } - - public int targetIndex() { - return (int) target; - } - - public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, ResolvedJavaField field) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.target = field; - } - - public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, int index) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.target = index; - } - - @Override - public void lower(LoweringTool tool, LoweringType loweringType) { - StructuredGraph graph = (StructuredGraph) graph(); - ResolvedJavaType type = object.objectStamp().type(); - FixedWithNextNode store; - if (target instanceof Integer) { - store = graph.add(new StoreIndexedNode(object, ConstantNode.forInt((int) target, graph), type.getComponentType().getKind(), value)); - } else { - assert target instanceof ResolvedJavaField; - store = graph.add(new StoreFieldNode(object, (ResolvedJavaField) target, value)); - } - graph.replaceFixedWithFixed(this, store); - } - - @Override - public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - if (state.getVirtualObject() instanceof VirtualArrayNode) { - tool.setVirtualEntry(state, targetIndex(), value()); - } else { - tool.setVirtualEntry(state, ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(targetField()), value()); - } - tool.delete(); - } - } -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.virtual.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; - -@NodeInfo(nameTemplate = "Materialize {i#virtualObject}") -public final class MaterializeObjectNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Node.IterableNodeType, Canonicalizable, ArrayLengthProvider { - - @Input private final NodeInputList values; - @Input private final VirtualObjectNode virtualObject; - private final int lockCount; - - public MaterializeObjectNode(VirtualObjectNode virtualObject, int lockCount) { - super(StampFactory.exactNonNull(virtualObject.type())); - this.virtualObject = virtualObject; - this.lockCount = lockCount; - this.values = new NodeInputList<>(this, virtualObject.entryCount()); - } - - public NodeInputList getValues() { - return values; - } - - public VirtualObjectNode getVirtualObject() { - return virtualObject; - } - - public int getLockCount() { - return lockCount; - } - - @Override - public ValueNode length() { - assert virtualObject.type().isArray(); - return ConstantNode.forInt(values.size(), graph()); - } - - /** - * @return true if the object that will be created is without locks and has only entries that - * are {@link Constant#defaultForKind(Kind)}, false otherwise. - */ - public boolean isDefault() { - if (lockCount > 0) { - return false; - } else { - for (ValueNode value : values) { - if (!value.isConstant() || !value.asConstant().isDefaultForKind()) { - return false; - } - } - } - return true; - } - - @Override - public void lower(LoweringTool tool, LoweringType loweringType) { - virtualObject.materializeAt(this, values, isDefault(), lockCount); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (usages().isEmpty()) { - return null; - } else { - return this; - } - } - - @Override - public void virtualize(VirtualizerTool tool) { - tool.createVirtualObject(virtualObject, values.toArray(new ValueNode[values.size()]), lockCount); - tool.replaceWithVirtual(virtualObject); - } -} diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon May 13 17:11:31 2013 +0200 @@ -26,14 +26,12 @@ import java.util.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.virtual.nodes.*; class BlockState { @@ -44,10 +42,10 @@ static class ReadCacheEntry { - public final Object identity; + public final LocationIdentity identity; public final ValueNode object; - public ReadCacheEntry(Object identity, ValueNode object) { + public ReadCacheEntry(LocationIdentity identity, ValueNode object) { this.identity = identity; this.object = object; } @@ -85,7 +83,7 @@ readCache = new HashMap<>(other.readCache); } - public void addReadCache(ValueNode object, Object identity, ValueNode value) { + public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value) { ValueNode cacheObject; ObjectState obj = getObjectState(object); if (obj != null) { @@ -97,7 +95,7 @@ readCache.put(new ReadCacheEntry(identity, cacheObject), value); } - public ValueNode getReadCache(ValueNode object, Object identity) { + public ValueNode getReadCache(ValueNode object, LocationIdentity identity) { ValueNode cacheObject; ObjectState obj = getObjectState(object); if (obj != null) { @@ -117,7 +115,7 @@ return cacheValue; } - public void killReadCache(Object identity) { + public void killReadCache(LocationIdentity identity) { if (identity == LocationNode.ANY_LOCATION) { readCache.clear(); } else { @@ -151,62 +149,51 @@ public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) { PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); - HashSet deferred = new HashSet<>(); - GraphEffectList deferredStores = new GraphEffectList(); - materializeChangedBefore(fixed, virtual, state, deferred, deferredStores, materializeEffects); - materializeEffects.addAll(deferredStores); + List objects = new ArrayList<>(2); + List values = new ArrayList<>(8); + List locks = new ArrayList<>(2); + List otherAllocations = new ArrayList<>(2); + materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state); + + materializeEffects.addMaterializationBefore(fixed, objects, locks, values, otherAllocations); } - private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, HashSet deferred, GraphEffectList deferredStores, - GraphEffectList materializeEffects) { - trace("materializing %s at %s", virtual, fixed); + private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List objects, List locks, List values, List otherAllocations, + EscapeState state) { + trace("materializing %s", virtual); ObjectState obj = getObjectState(virtual); - if (obj.getLockCount() > 0 && obj.virtual.type().isArray()) { - throw new BailoutException("array materialized with lock"); - } - - ValueNode[] fieldState = obj.getEntries(); - MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount()); - ValueNode[] values = new ValueNode[obj.getEntries().length]; - obj.escape(materialize, state); - deferred.add(virtual); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = getObjectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.isVirtual()) { - materializeChangedBefore(fixed, valueObj.virtual, state, deferred, deferredStores, materializeEffects); + ValueNode[] entries = obj.getEntries(); + ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks()); + obj.escape(representation, state); + if (representation instanceof AllocatedObjectNode) { + objects.add((AllocatedObjectNode) representation); + locks.add(obj.getLocks()); + int pos = values.size(); + while (values.size() < pos + entries.length) { + values.add(null); + } + for (int i = 0; i < entries.length; i++) { + ObjectState entryObj = getObjectState(entries[i]); + if (entryObj != null) { + if (entryObj.isVirtual()) { + materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state); + } + values.set(pos + i, entryObj.getMaterializedValue()); + } else { + values.set(pos + i, entries[i]); } - if (deferred.contains(valueObj.virtual)) { - Kind fieldKind; - CyclicMaterializeStoreNode store; - if (virtual instanceof VirtualArrayNode) { - store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), i); - fieldKind = ((VirtualArrayNode) virtual).componentType().getKind(); - } else { - VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual; - store = new CyclicMaterializeStoreNode(materialize, valueObj.getMaterializedValue(), instanceObject.field(i)); - fieldKind = instanceObject.field(i).getType().getKind(); - } - deferredStores.addFixedNodeBefore(store, fixed); - values[i] = ConstantNode.defaultForKind(fieldKind, fixed.graph()); - } else { - values[i] = valueObj.getMaterializedValue(); + } + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < entries.length; i++) { + readCache.put(new ReadCacheEntry((LocationIdentity) instance.field(i), representation), values.get(pos + i)); } - } else { - values[i] = fieldState[i]; } + } else { + otherAllocations.add(representation); + assert obj.getLocks().length == 0; } - deferred.remove(virtual); - - if (virtual instanceof VirtualInstanceNode) { - VirtualInstanceNode instance = (VirtualInstanceNode) virtual; - for (int i = 0; i < fieldState.length; i++) { - readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]); - } - } - - materializeEffects.addMaterialization(materialize, fixed, values); } void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon May 13 17:11:31 2013 +0200 @@ -26,10 +26,10 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.virtual.nodes.*; public class GraphEffectList extends EffectList { @@ -118,33 +118,6 @@ } /** - * Add the materialization node to the graph's control flow at the given position, and then sets - * its values. - * - * @param node The materialization node that should be added. - * @param position The fixed node before which the materialization node should be added. - * @param values The values for the materialization node's entries. - */ - public void addMaterialization(final MaterializeObjectNode node, final FixedNode position, final ValueNode[] values) { - add(new Effect() { - - @Override - public String name() { - return "addMaterialization"; - } - - @Override - public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { - assert !node.isAlive() && !node.isDeleted() && position.isAlive(); - graph.addBeforeFixed(position, graph.add(node)); - for (int i = 0; i < values.length; i++) { - node.getValues().set(i, values[i]); - } - } - }); - } - - /** * Adds an value to the given phi node. * * @param node The phi node to which the value should be added. @@ -330,4 +303,68 @@ } }); } + + /** + * Add the materialization node to the graph's control flow at the given position, and then sets + * its values. + * + * @param position The fixed node before which the materialization node should be added. + * @param objects The allocated objects. + * @param locks The lock depths for each object. + * @param values The values (field, elements) of all objects. + * @param otherAllocations A list of allocations that need to be added before the rest (used for + * boxing allocations). + */ + public void addMaterializationBefore(final FixedNode position, final List objects, final List locks, final List values, + final List otherAllocations) { + add(new Effect() { + + @Override + public String name() { + return "addMaterializationBefore"; + } + + @Override + public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { + for (ValueNode otherAllocation : otherAllocations) { + graph.add(otherAllocation); + if (otherAllocation instanceof FixedWithNextNode) { + graph.addBeforeFixed(position, (FixedWithNextNode) otherAllocation); + } else { + assert otherAllocation instanceof FloatingNode; + } + } + if (!objects.isEmpty()) { + CommitAllocationNode commit; + if (position.predecessor() instanceof CommitAllocationNode) { + commit = (CommitAllocationNode) position.predecessor(); + } else { + commit = graph.add(new CommitAllocationNode()); + graph.addBeforeFixed(position, commit); + } + for (AllocatedObjectNode obj : objects) { + graph.add(obj); + commit.getVirtualObjects().add(obj.getVirtualObject()); + obj.setCommit(commit); + } + commit.getValues().addAll(values); + commit.getLocks().addAll(locks); + + assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.usages().count(); + HashSet materializedValues = new HashSet<>(commit.usages().filter(AllocatedObjectNode.class).snapshot()); + for (int i = 0; i < commit.getValues().size(); i++) { + if (materializedValues.contains(commit.getValues().get(i))) { + commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject()); + } + } + + } + } + + @Override + public boolean isVisible() { + return true; + } + }); + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Mon May 13 17:11:31 2013 +0200 @@ -36,32 +36,69 @@ */ class ObjectState extends Virtualizable.State { - public final VirtualObjectNode virtual; + private static final int[] EMPTY_INT_ARRAY = new int[0]; + + public static final class LockState { + + public final int depth; + public final LockState next; + + private LockState(int depth, LockState next) { + this.depth = depth; + this.next = next; + } + + @Override + public String toString() { + return next == null ? String.valueOf(depth) : depth + "," + next; + } + + public static boolean equals(LockState a, LockState b) { + if ((a == null) != (b == null)) { + return false; + } + if (a != null) { + if (a.depth != b.depth) { + return false; + } + return equals(a.next, b.next); + } + return true; + } + } + + final VirtualObjectNode virtual; private EscapeState state; private ValueNode[] entries; private ValueNode materializedValue; - private int lockCount; + private LockState locks; - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int lockCount) { + public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, int[] locks) { this.virtual = virtual; this.entries = entries; this.state = state; - this.lockCount = lockCount; + if (locks == null) { + this.locks = null; + } else { + for (int i = locks.length - 1; i >= 0; i--) { + this.locks = new LockState(locks[i], this.locks); + } + } } - public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, int lockCount) { + public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) { this.virtual = virtual; this.materializedValue = materializedValue; this.state = state; - this.lockCount = lockCount; + this.locks = locks; } private ObjectState(ObjectState other) { virtual = other.virtual; entries = other.entries == null ? null : other.entries.clone(); materializedValue = other.materializedValue; - lockCount = other.lockCount; + locks = other.locks; state = other.state; } @@ -120,24 +157,56 @@ } @Override - public int getLockCount() { - return lockCount; + public void addLock(int depth) { + locks = new LockState(depth, locks); } @Override - public void setLockCount(int lockCount) { - this.lockCount = lockCount; + public int removeLock() { + try { + return locks.depth; + } finally { + locks = locks.next; + } + } + + public int[] getLocks() { + if (locks == null) { + return EMPTY_INT_ARRAY; + } + int cnt = 0; + LockState current = locks; + while (current != null) { + cnt++; + current = current.next; + } + int[] result = new int[cnt]; + current = locks; + cnt = 0; + while (current != null) { + result[cnt++] = current.depth; + current = current.next; + } + return result; + } + + public boolean hasLocks() { + return locks != null; + } + + public boolean locksEqual(ObjectState other) { + return LockState.equals(locks, other.locks); } @Override public String toString() { StringBuilder str = new StringBuilder().append('{'); - if (lockCount > 0) { - str.append('l').append(lockCount).append(' '); + if (locks != null) { + str.append('l').append(locks).append(' '); } if (entries != null) { for (int i = 0; i < entries.length; i++) { - str.append(virtual.fieldName(i)).append('=').append(entries[i]).append(' '); + str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' '); } } if (materializedValue != null) { @@ -152,7 +221,7 @@ final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(entries); - result = prime * result + lockCount; + result = prime * result + (locks != null ? locks.depth : 0); result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); result = prime * result + ((state == null) ? 0 : state.hashCode()); result = prime * result + ((virtual == null) ? 0 : virtual.hashCode()); @@ -171,7 +240,7 @@ if (!Arrays.equals(entries, other.entries)) { return false; } - if (lockCount != other.lockCount) { + if (!LockState.equals(locks, other.locks)) { return false; } if (materializedValue == null) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon May 13 17:11:31 2013 +0200 @@ -32,13 +32,13 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.nodes.*; public class PartialEscapeAnalysisPhase extends BasePhase { @@ -126,8 +126,13 @@ private static boolean matches(StructuredGraph graph, String filter) { if (filter != null) { - ResolvedJavaMethod method = graph.method(); - return method != null && MetaUtil.format("%H.%n", method).contains(filter); + if (filter.startsWith("~")) { + ResolvedJavaMethod method = graph.method(); + return method == null || !MetaUtil.format("%H.%n", method).contains(filter.substring(1)); + } else { + ResolvedJavaMethod method = graph.method(); + return method != null && MetaUtil.format("%H.%n", method).contains(filter); + } } return true; } @@ -139,8 +144,8 @@ IdentityHashMap path = new IdentityHashMap<>(); flood.add(graph.start()); for (Node current : flood) { - if (current instanceof EndNode) { - EndNode end = (EndNode) current; + if (current instanceof AbstractEndNode) { + AbstractEndNode end = (AbstractEndNode) current; flood.add(end.merge()); if (!path.containsKey(end.merge())) { path.put(end.merge(), end); @@ -203,32 +208,36 @@ public static Map getHints(StructuredGraph graph) { NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply(); Map hints = null; - for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { + for (CommitAllocationNode commit : graph.getNodes(CommitAllocationNode.class)) { double sum = 0; double invokeSum = 0; - for (Node usage : materialize.usages()) { - if (usage instanceof FixedNode) { - sum += probabilities.get((FixedNode) usage); - } else { - if (usage instanceof MethodCallTargetNode) { - invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode()); - } - for (Node secondLevelUage : materialize.usages()) { - if (secondLevelUage instanceof FixedNode) { - sum += probabilities.get(((FixedNode) secondLevelUage)); + for (Node commitUsage : commit.usages()) { + for (Node usage : commitUsage.usages()) { + if (usage instanceof FixedNode) { + sum += probabilities.get((FixedNode) usage); + } else { + if (usage instanceof MethodCallTargetNode) { + invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode()); + } + for (Node secondLevelUage : usage.usages()) { + if (secondLevelUage instanceof FixedNode) { + sum += probabilities.get(((FixedNode) secondLevelUage)); + } } } } } // TODO(lstadler) get rid of this magic number if (sum > 100 && invokeSum > 0) { - for (Node usage : materialize.usages()) { - if (usage instanceof MethodCallTargetNode) { - if (hints == null) { - hints = new HashMap<>(); + for (Node commitUsage : commit.usages()) { + for (Node usage : commitUsage.usages()) { + if (usage instanceof MethodCallTargetNode) { + if (hints == null) { + hints = new HashMap<>(); + } + Invoke invoke = ((MethodCallTargetNode) usage).invoke(); + hints.put(invoke, sum / invokeSum); } - Invoke invoke = ((MethodCallTargetNode) usage).invoke(); - hints.put(invoke, sum / invokeSum); } } } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon May 13 17:11:31 2013 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @@ -91,7 +92,7 @@ public List applyEffects(final StructuredGraph graph) { final ArrayList obsoleteNodes = new ArrayList<>(); - BlockIteratorClosure closure = new BlockIteratorClosure() { + BlockIteratorClosure closure = new BlockIteratorClosure() { private void apply(GraphEffectList effects, Object context) { if (!effects.isEmpty()) { @@ -106,28 +107,29 @@ } @Override - protected void processBlock(Block block, Object currentState) { + protected Void processBlock(Block block, Void currentState) { apply(blockEffects.get(block), block); + return currentState; } @Override - protected Object merge(Block merge, List states) { - return new Object(); + protected Void merge(Block merge, List states) { + return null; } @Override - protected Object cloneState(Object oldState) { + protected Void cloneState(Void oldState) { return oldState; } @Override - protected List processLoop(Loop loop, Object initialState) { - LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, initialState); + protected List processLoop(Loop loop, Void initialState) { + LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, initialState); apply(loopMergeEffects.get(loop), loop); return info.exitStates; } }; - ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new Object(), null); + ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), null, null); return obsoleteNodes; } @@ -136,7 +138,7 @@ } @Override - protected void processBlock(Block block, BlockState state) { + protected BlockState processBlock(Block block, BlockState state) { GraphEffectList effects = blockEffects.get(block); tool.setEffects(effects); @@ -158,18 +160,18 @@ if (node instanceof StoreFieldNode) { METRIC_STOREFIELD_RECORDED.increment(); StoreFieldNode store = (StoreFieldNode) node; - ValueNode cachedValue = state.getReadCache(store.object(), store.field()); - state.killReadCache(store.field()); + ValueNode cachedValue = state.getReadCache(store.object(), (LocationIdentity) store.field()); + state.killReadCache((LocationIdentity) store.field()); if (cachedValue == store.value()) { effects.deleteFixedNode(store); changed = true; } else { - state.addReadCache(store.object(), store.field(), store.value()); + state.addReadCache(store.object(), (LocationIdentity) store.field(), store.value()); } } else if (node instanceof LoadFieldNode) { LoadFieldNode load = (LoadFieldNode) node; - ValueNode cachedValue = state.getReadCache(load.object(), load.field()); + ValueNode cachedValue = state.getReadCache(load.object(), (LocationIdentity) load.field()); if (cachedValue != null) { METRIC_LOADFIELD_ELIMINATED.increment(); effects.replaceAtUsages(load, cachedValue); @@ -177,12 +179,12 @@ changed = true; } else { METRIC_LOADFIELD_NOT_ELIMINATED.increment(); - state.addReadCache(load.object(), load.field(), load); + state.addReadCache(load.object(), (LocationIdentity) load.field(), load); } } else if (node instanceof MemoryCheckpoint) { METRIC_MEMORYCHECKOINT.increment(); MemoryCheckpoint checkpoint = (MemoryCheckpoint) node; - for (Object identity : checkpoint.getLocationIdentities()) { + for (LocationIdentity identity : checkpoint.getLocationIdentities()) { state.killReadCache(identity); } } @@ -193,15 +195,16 @@ } } trace(")\n end state: %s\n", state); + return state; } private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) { - tool.reset(state, node); + tool.reset(state, node, insertBefore); if (node instanceof Virtualizable) { ((Virtualizable) node).virtualize(tool); } if (tool.isDeleted()) { - if (tool.isCustomAction() || !(node instanceof VirtualizableAllocation || node instanceof CyclicMaterializeStoreNode)) { + if (!(node instanceof VirtualizableAllocation)) { changed = true; } return true; @@ -238,7 +241,7 @@ } }); for (ObjectState obj : state.getStates()) { - if (obj.isVirtual() && obj.getLockCount() > 0) { + if (obj.isVirtual() && obj.hasLocks()) { virtual.add(obj); } } @@ -280,9 +283,6 @@ } } } - if (tool.isCustomAction()) { - return false; - } for (ValueNode input : node.inputs().filter(ValueNode.class)) { ObjectState obj = state.getObjectState(input); if (obj != null) { @@ -502,7 +502,6 @@ } int virtual = 0; ObjectState startObj = objStates[0]; - int lockCount = startObj.getLockCount(); boolean locksMatch = true; ValueNode singleValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); for (ObjectState obj : objStates) { @@ -514,7 +513,7 @@ singleValue = null; } } - locksMatch &= obj.getLockCount() == lockCount; + locksMatch &= obj.locksEqual(startObj); } assert virtual < states.size() || locksMatch : "mismatching lock counts at " + merge; @@ -531,9 +530,9 @@ ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, lockCount)); + newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, null)); } else { - newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, lockCount)); + newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, null)); } } else { assert virtual == states.size(); @@ -567,7 +566,7 @@ values[index] = phis[index]; } } - newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, lockCount)); + newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, startObj.getLocks())); } } @@ -638,7 +637,7 @@ } } mergeEffects.addFloatingNode(virtual, "valueObjectNode"); - newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, 0)); + newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null)); newState.addAndMarkAlias(virtual, virtual, usages); newState.addAndMarkAlias(virtual, phi, usages); } else { @@ -704,7 +703,7 @@ } } - private void mergeReadCachePhi(PhiNode phi, Object identity, List states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List states) { ValueNode[] values = new ValueNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Mon May 13 17:11:31 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.spi.*; @@ -48,9 +49,9 @@ } private boolean deleted; - private boolean customAction; private BlockState state; private ValueNode current; + private FixedNode position; @Override public MetaAccessProvider getMetaAccessProvider() { @@ -66,21 +67,17 @@ this.effects = effects; } - public void reset(BlockState newState, ValueNode newCurrent) { + public void reset(BlockState newState, ValueNode newCurrent, FixedNode newPosition) { deleted = false; - customAction = false; - this.state = newState; - this.current = newCurrent; + state = newState; + current = newCurrent; + position = newPosition; } public boolean isDeleted() { return deleted; } - public boolean isCustomAction() { - return customAction; - } - @Override public State getObjectState(ValueNode value) { return state.getObjectState(value); @@ -142,13 +139,16 @@ } @Override - public void customAction(Runnable action) { - effects.customAction(action); - customAction = true; + public void addNode(ValueNode node) { + if (node instanceof FloatingNode) { + effects.addFloatingNode(node, "VirtualizerTool"); + } else { + effects.addFixedNodeBefore((FixedWithNextNode) node, position); + } } @Override - public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int lockCount) { + public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) { trace("{{%s}} ", current); if (virtualObject.isAlive()) { state.addAndMarkAlias(virtualObject, virtualObject, usages); @@ -158,7 +158,7 @@ for (int i = 0; i < entryState.length; i++) { entryState[i] = state.getScalarAlias(entryState[i]); } - state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, lockCount)); + state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks)); state.addAndMarkAlias(virtualObject, virtualObject, usages); PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment(); } diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Mon May 13 17:11:31 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.word; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; public interface Pointer extends Unsigned { @@ -47,7 +48,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - byte readByte(WordBase offset, Object locationIdentity); + byte readByte(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -61,7 +62,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - char readChar(WordBase offset, Object locationIdentity); + char readChar(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -75,7 +76,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - short readShort(WordBase offset, Object locationIdentity); + short readShort(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -89,7 +90,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - int readInt(WordBase offset, Object locationIdentity); + int readInt(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -103,7 +104,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - long readLong(WordBase offset, Object locationIdentity); + long readLong(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -117,7 +118,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - float readFloat(WordBase offset, Object locationIdentity); + float readFloat(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -131,7 +132,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - double readDouble(WordBase offset, Object locationIdentity); + double readDouble(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -145,7 +146,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - Word readWord(WordBase offset, Object locationIdentity); + Word readWord(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -159,7 +160,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - Object readObject(WordBase offset, Object locationIdentity); + Object readObject(WordBase offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -169,7 +170,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - byte readByte(int offset, Object locationIdentity); + byte readByte(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -179,7 +180,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - char readChar(int offset, Object locationIdentity); + char readChar(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -189,7 +190,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - short readShort(int offset, Object locationIdentity); + short readShort(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -199,7 +200,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - int readInt(int offset, Object locationIdentity); + int readInt(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -209,7 +210,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - long readLong(int offset, Object locationIdentity); + long readLong(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -219,7 +220,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - float readFloat(int offset, Object locationIdentity); + float readFloat(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -229,7 +230,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - double readDouble(int offset, Object locationIdentity); + double readDouble(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -239,7 +240,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - Word readWord(int offset, Object locationIdentity); + Word readWord(int offset, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -249,7 +250,7 @@ * @param locationIdentity the identity of the read (see {@link LocationNode}) * @return the result of the memory access */ - Object readObject(int offset, Object locationIdentity); + Object readObject(int offset, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -263,7 +264,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeByte(WordBase offset, byte val, Object locationIdentity); + void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -277,7 +278,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeChar(WordBase offset, char val, Object locationIdentity); + void writeChar(WordBase offset, char val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -291,7 +292,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeShort(WordBase offset, short val, Object locationIdentity); + void writeShort(WordBase offset, short val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -305,7 +306,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeInt(WordBase offset, int val, Object locationIdentity); + void writeInt(WordBase offset, int val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -319,7 +320,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeLong(WordBase offset, long val, Object locationIdentity); + void writeLong(WordBase offset, long val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -333,7 +334,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeFloat(WordBase offset, float val, Object locationIdentity); + void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -347,7 +348,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeDouble(WordBase offset, double val, Object locationIdentity); + void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -361,7 +362,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeWord(WordBase offset, WordBase val, Object locationIdentity); + void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -375,7 +376,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeObject(WordBase offset, Object val, Object locationIdentity); + void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -385,7 +386,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeByte(int offset, byte val, Object locationIdentity); + void writeByte(int offset, byte val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -395,7 +396,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeChar(int offset, char val, Object locationIdentity); + void writeChar(int offset, char val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -405,7 +406,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeShort(int offset, short val, Object locationIdentity); + void writeShort(int offset, short val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -415,7 +416,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeInt(int offset, int val, Object locationIdentity); + void writeInt(int offset, int val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -425,7 +426,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeLong(int offset, long val, Object locationIdentity); + void writeLong(int offset, long val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -435,7 +436,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeFloat(int offset, float val, Object locationIdentity); + void writeFloat(int offset, float val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -445,7 +446,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeDouble(int offset, double val, Object locationIdentity); + void writeDouble(int offset, double val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -455,7 +456,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeWord(int offset, WordBase val, Object locationIdentity); + void writeWord(int offset, WordBase val, LocationIdentity locationIdentity); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in @@ -465,7 +466,7 @@ * @param locationIdentity the identity of the write (see {@link LocationNode}) * @param val the value to be written to memory */ - void writeObject(int offset, Object val, Object locationIdentity); + void writeObject(int offset, Object val, LocationIdentity locationIdentity); /** * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Mon May 13 17:11:31 2013 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; public abstract class Word implements Signed, Unsigned, Pointer { @@ -601,215 +602,215 @@ @Override @Operation(opcode = Opcode.READ) - public byte readByte(WordBase offset, Object locationIdentity) { + public byte readByte(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getByte(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public char readChar(WordBase offset, Object locationIdentity) { + public char readChar(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getChar(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public short readShort(WordBase offset, Object locationIdentity) { + public short readShort(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getShort(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public int readInt(WordBase offset, Object locationIdentity) { + public int readInt(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getInt(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public long readLong(WordBase offset, Object locationIdentity) { + public long readLong(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getLong(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public float readFloat(WordBase offset, Object locationIdentity) { + public float readFloat(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getFloat(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public double readDouble(WordBase offset, Object locationIdentity) { + public double readDouble(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getDouble(add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public Word readWord(WordBase offset, Object locationIdentity) { + public Word readWord(WordBase offset, LocationIdentity locationIdentity) { return box(unsafe.getAddress(add((Word) offset).unbox())); } @Override @Operation(opcode = Opcode.READ) - public Object readObject(WordBase offset, Object locationIdentity) { + public Object readObject(WordBase offset, LocationIdentity locationIdentity) { return unsafe.getObject(null, add((Word) offset).unbox()); } @Override @Operation(opcode = Opcode.READ) - public byte readByte(int offset, Object locationIdentity) { + public byte readByte(int offset, LocationIdentity locationIdentity) { return readByte(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public char readChar(int offset, Object locationIdentity) { + public char readChar(int offset, LocationIdentity locationIdentity) { return readChar(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public short readShort(int offset, Object locationIdentity) { + public short readShort(int offset, LocationIdentity locationIdentity) { return readShort(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public int readInt(int offset, Object locationIdentity) { + public int readInt(int offset, LocationIdentity locationIdentity) { return readInt(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public long readLong(int offset, Object locationIdentity) { + public long readLong(int offset, LocationIdentity locationIdentity) { return readLong(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public float readFloat(int offset, Object locationIdentity) { + public float readFloat(int offset, LocationIdentity locationIdentity) { return readFloat(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public double readDouble(int offset, Object locationIdentity) { + public double readDouble(int offset, LocationIdentity locationIdentity) { return readDouble(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public Word readWord(int offset, Object locationIdentity) { + public Word readWord(int offset, LocationIdentity locationIdentity) { return readWord(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ) - public Object readObject(int offset, Object locationIdentity) { + public Object readObject(int offset, LocationIdentity locationIdentity) { return readObject(signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeByte(WordBase offset, byte val, Object locationIdentity) { + public void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity) { unsafe.putByte(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeChar(WordBase offset, char val, Object locationIdentity) { + public void writeChar(WordBase offset, char val, LocationIdentity locationIdentity) { unsafe.putChar(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeShort(WordBase offset, short val, Object locationIdentity) { + public void writeShort(WordBase offset, short val, LocationIdentity locationIdentity) { unsafe.putShort(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeInt(WordBase offset, int val, Object locationIdentity) { + public void writeInt(WordBase offset, int val, LocationIdentity locationIdentity) { unsafe.putInt(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeLong(WordBase offset, long val, Object locationIdentity) { + public void writeLong(WordBase offset, long val, LocationIdentity locationIdentity) { unsafe.putLong(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeFloat(WordBase offset, float val, Object locationIdentity) { + public void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity) { unsafe.putFloat(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeDouble(WordBase offset, double val, Object locationIdentity) { + public void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity) { unsafe.putDouble(add((Word) offset).unbox(), val); } @Override @Operation(opcode = Opcode.WRITE) - public void writeWord(WordBase offset, WordBase val, Object locationIdentity) { + public void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) { unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox()); } @Override @Operation(opcode = Opcode.WRITE) - public native void writeObject(WordBase offset, Object val, Object locationIdentity); + public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); @Override @Operation(opcode = Opcode.WRITE) - public void writeByte(int offset, byte val, Object locationIdentity) { + public void writeByte(int offset, byte val, LocationIdentity locationIdentity) { writeByte(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeChar(int offset, char val, Object locationIdentity) { + public void writeChar(int offset, char val, LocationIdentity locationIdentity) { writeChar(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeShort(int offset, short val, Object locationIdentity) { + public void writeShort(int offset, short val, LocationIdentity locationIdentity) { writeShort(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeInt(int offset, int val, Object locationIdentity) { + public void writeInt(int offset, int val, LocationIdentity locationIdentity) { writeInt(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeLong(int offset, long val, Object locationIdentity) { + public void writeLong(int offset, long val, LocationIdentity locationIdentity) { writeLong(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeFloat(int offset, float val, Object locationIdentity) { + public void writeFloat(int offset, float val, LocationIdentity locationIdentity) { writeFloat(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeDouble(int offset, double val, Object locationIdentity) { + public void writeDouble(int offset, double val, LocationIdentity locationIdentity) { writeDouble(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeWord(int offset, WordBase val, Object locationIdentity) { + public void writeWord(int offset, WordBase val, LocationIdentity locationIdentity) { writeWord(signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE) - public void writeObject(int offset, Object val, Object locationIdentity) { + public void writeObject(int offset, Object val, LocationIdentity locationIdentity) { writeObject(signed(offset), val, locationIdentity); } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon May 13 17:11:31 2013 +0200 @@ -29,7 +29,8 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.extended.WriteNode.*; +import com.oracle.graal.nodes.extended.LocationNode.LocationIdentity; +import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -44,11 +45,13 @@ */ public class WordTypeRewriterPhase extends Phase { + private final MetaAccessProvider metaAccess; private final ResolvedJavaType wordBaseType; private final ResolvedJavaType wordImplType; private final Kind wordKind; public WordTypeRewriterPhase(MetaAccessProvider metaAccess, Kind wordKind) { + this.metaAccess = metaAccess; this.wordKind = wordKind; this.wordBaseType = metaAccess.lookupJavaType(WordBase.class); this.wordImplType = metaAccess.lookupJavaType(Word.class); @@ -103,9 +106,27 @@ } } - for (LoadIndexedNode load : graph.getNodes().filter(LoadIndexedNode.class).snapshot()) { - if (isWord(load)) { - load.setStamp(StampFactory.forKind(wordKind)); + for (AccessIndexedNode node : graph.getNodes().filter(AccessIndexedNode.class).snapshot()) { + ValueNode array = node.array(); + if (array.objectStamp().type() == null) { + // There are cases where the array does not have a known type yet. Assume it is not + // a word type. + continue; + } + assert array.objectStamp().type().isArray(); + if (isWord(array.objectStamp().type().getComponentType())) { + /* + * The elementKind of the node is a final field, and other information such as the + * stamp depends on elementKind. Therefore, just create a new node and replace the + * old one. + */ + if (node instanceof LoadIndexedNode) { + graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind))); + } else if (node instanceof StoreIndexedNode) { + graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value()))); + } else { + throw GraalInternalError.shouldNotReachHere(); + } } } @@ -138,20 +159,30 @@ replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph)))); break; - case READ: + case READ: { assert arguments.size() == 2 || arguments.size() == 3; Kind readKind = asKind(callTargetNode.returnType()); - Object readLocation = arguments.size() == 2 ? LocationNode.ANY_LOCATION : arguments.get(2).asConstant().asObject(); - replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation)); + LocationNode location; + if (arguments.size() == 2) { + location = makeLocation(graph, arguments.get(1), readKind, LocationNode.ANY_LOCATION); + } else { + location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2)); + } + replace(invoke, readOp(graph, arguments.get(0), invoke, location)); break; - - case WRITE: + } + case WRITE: { assert arguments.size() == 3 || arguments.size() == 4; Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass())); - Object writeLocation = arguments.size() == 3 ? LocationNode.ANY_LOCATION : arguments.get(3).asConstant().asObject(); - replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, writeLocation)); + LocationNode location; + if (arguments.size() == 3) { + location = makeLocation(graph, arguments.get(1), writeKind, LocationNode.ANY_LOCATION); + } else { + location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3)); + } + replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location)); break; - + } case ZERO: assert arguments.size() == 0; replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph)); @@ -266,18 +297,27 @@ return materialize; } - private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Kind readKind, Object locationIdentity) { - IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1); + private LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, ValueNode locationIdentity) { + if (locationIdentity.isConstant()) { + return makeLocation(graph, offset, readKind, (LocationIdentity) locationIdentity.asConstant().asObject()); + } + return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), offset, ConstantNode.forInt(1, graph), graph); + } + + private static LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) { + return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1); + } + + private static ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location) { ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp())); graph.addBeforeFixed(invoke.asNode(), read); // The read must not float outside its block otherwise it may float above an explicit zero // check on its base address - read.dependencies().add(BeginNode.prevBegin(invoke.asNode())); + read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode())); return read; } - private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Kind writeKind, Object locationIdentity) { - IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1); + private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location) { WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE)); write.setStateAfter(invoke.stateAfter()); graph.addBeforeFixed(invoke.asNode(), write); @@ -309,16 +349,6 @@ if (node.stamp() == StampFactory.forWord()) { return true; } - if (node instanceof LoadIndexedNode) { - ValueNode array = ((LoadIndexedNode) node).array(); - if (array.objectStamp().type() == null) { - // There are cases where the array does not have a known type yet. Assume it is not - // a word type. - // TODO disallow LoadIndexedNode for word arrays? - return false; - } - return isWord(array.objectStamp().type().getComponentType()); - } if (node.kind() == Kind.Object) { return isWord(node.objectStamp().type()); } @@ -344,7 +374,7 @@ if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) { WordBase value = (WordBase) valueNode.asConstant().asObject(); ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), valueNode.graph()); - ((StructuredGraph) valueNode.graph()).replaceFloating((ConstantNode) valueNode, newConstant); + valueNode.graph().replaceFloating((ConstantNode) valueNode, newConstant); } else { assert !(valueNode instanceof ConstantNode) : "boxed Word constants should not appear in a snippet graph: " + valueNode + ", stamp: " + valueNode.stamp(); valueNode.setStamp(StampFactory.forKind(wordKind)); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Mon May 13 17:11:31 2013 +0200 @@ -115,7 +115,7 @@ @Override public Object execute(VirtualFrame frame) { invocationCount++; - return ((TestArguments) frame.getArguments()).get(index); + return frame.getArguments(TestArguments.class).get(index); } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Mon May 13 17:11:31 2013 +0200 @@ -35,7 +35,7 @@ * A guest language can pass its own custom arguments when invoking a Truffle method by creating a * subclass of {@link Arguments}. When invoking a call target with * {@link CallTarget#call(Arguments)}, the arguments can be passed. A Truffle node can access the - * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}. + * arguments passed into the Truffle method by using {@link VirtualFrame#getArguments}. *

    * *

    @@ -97,7 +97,7 @@ } int execute(VirtualFrame frame) { - return ((TestArguments) frame.getArguments()).values[index]; + return frame.getArguments(TestArguments.class).values[index]; } } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Mon May 13 17:11:31 2013 +0200 @@ -117,4 +117,13 @@ @Target({ElementType.FIELD}) public @interface CompilationFinal { } + + /** + * Marks methods that are considered unsafe. Wrong usage of those methods can lead to unexpected + * behavior including a crash of the runtime. Therefore, special care should be taken. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + public @interface Unsafe { + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Mon May 13 17:11:31 2013 +0200 @@ -117,4 +117,10 @@ public final String getCode() { return getSource().getCode().substring(charIndex, charLength); } + + @Override + public String toString() { + return String.format("%s:%d", source.getName(), startLine); + } + } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Mon May 13 17:11:31 2013 +0200 @@ -36,9 +36,17 @@ FrameDescriptor getFrameDescriptor(); /** + * Retrieves the arguments object from this frame. The runtime assumes that the arguments object + * is never null. Additionally, the runtime may assume that the given parameter indicating the + * class of the arguments object is correct. The runtime is not required to actually check the + * type of the arguments object. The parameter must be a value that can be reduced to a compile + * time constant. + * + * @param clazz the known type of the arguments object as a compile time constant * @return the arguments used when calling this method */ - Arguments getArguments(); + @CompilerDirectives.Unsafe + T getArguments(Class clazz); /** * Read access to a local variable of type {@link Object}. diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Mon May 13 17:11:31 2013 +0200 @@ -50,7 +50,7 @@ } public FrameSlot addFrameSlot(Object identifier) { - return addFrameSlot(identifier, null); + return addFrameSlot(identifier, FrameSlotKind.Illegal); } public FrameSlot addFrameSlot(Object identifier, FrameSlotKind kind) { diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Mon May 13 17:11:31 2013 +0200 @@ -38,9 +38,10 @@ this.arguments = arguments; } + @SuppressWarnings("unchecked") @Override - public Arguments getArguments() { - return arguments; + public T getArguments(Class clazz) { + return (T) arguments; } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Mon May 13 17:11:31 2013 +0200 @@ -34,8 +34,8 @@ } @Override - public Arguments getArguments() { - return wrapped.getArguments(); + public T getArguments(Class clazz) { + return wrapped.getArguments(clazz); } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Mon May 13 17:11:31 2013 +0200 @@ -43,9 +43,10 @@ this.tags = new byte[descriptor.getSize()]; } + @SuppressWarnings("unchecked") @Override - public Arguments getArguments() { - return arguments; + public T getArguments(Class clazz) { + return (T) arguments; } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Mon May 13 17:11:31 2013 +0200 @@ -334,7 +334,7 @@ // default handler createElementForNode(node); - List children = NodeUtil.findNodeChildren(node); + List children = NodeUtil.findNodeChildren((Node) node); for (Object child : children) { if (child == null) { continue; diff -r 57113d21ce36 -r f9a65a0e626b 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 Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon May 13 17:11:31 2013 +0200 @@ -29,6 +29,9 @@ import sun.misc.*; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.nodes.Node.Children; + /** * Utility class that manages the special access methods for node instances. */ @@ -73,15 +76,13 @@ } // Node fields - if (Node.class.isAssignableFrom(field.getType())) { - if (!field.getName().equals("parent")) { - nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field)); - nodeFieldClassesList.add(field.getType()); - } else { - parentOffsetTemp = unsafe.objectFieldOffset(field); - parentClassTmp = field.getType(); - } - } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType())) { + if (Node.class.isAssignableFrom(field.getType()) && field.getName().equals("parent")) { + parentOffsetTemp = unsafe.objectFieldOffset(field); + parentClassTmp = field.getType(); + } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { + nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field)); + nodeFieldClassesList.add(field.getType()); + } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field)); nodeArrayFieldClassesList.add(field.getType()); } else { @@ -234,7 +235,8 @@ for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset); if (children != null) { - Node[] clonedChildren = new Node[children.length]; + Node[] clonedChildren = children.clone(); + Arrays.fill(clonedChildren, null); for (int i = 0; i < children.length; i++) { Node clonedChild = cloneNode(children[i]); if (clonedChild == null) { @@ -250,18 +252,18 @@ return (T) clone; } - public static List findNodeChildren(Object node) { - List nodes = new ArrayList<>(); + public static List findNodeChildren(Node node) { + List nodes = new ArrayList<>(); NodeClass nodeClass = NodeClass.get(node.getClass()); for (long fieldOffset : nodeClass.nodeFieldOffsets) { Object child = unsafe.getObject(node, fieldOffset); if (child != null) { - nodes.add(child); + nodes.add((Node) child); } } for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { - Object[] children = (Object[]) unsafe.getObject(node, fieldOffset); + Node[] children = (Node[]) unsafe.getObject(node, fieldOffset); if (children != null) { nodes.addAll(Arrays.asList(children)); } @@ -385,14 +387,15 @@ } @SuppressWarnings("unchecked") - public static T findFirstNodeInstance(Object root, Class clazz) { - List childNodes = findNodeChildren(root); - - for (Object childNode : childNodes) { + public static T findFirstNodeInstance(Node root, Class clazz) { + for (Node childNode : findNodeChildren(root)) { if (clazz.isInstance(childNode)) { return (T) childNode; } else { - return findFirstNodeInstance(childNode, clazz); + T node = findFirstNodeInstance(childNode, clazz); + if (node != null) { + return node; + } } } return null; @@ -470,8 +473,16 @@ } public static String printTreeToString(Node node) { + return printTreeToString(node, false); + } + + private static String printTreeToString(Node node, boolean compact) { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - printTree(new PrintStream(byteOut), node); + if (compact) { + printCompactTree(new PrintStream(byteOut), node); + } else { + printTree(new PrintStream(byteOut), node); + } try { byteOut.flush(); } catch (IOException e) { @@ -490,6 +501,61 @@ printTree(p, node, new NodeTreeResolver()); } + public static String printCompactTreeToString(Node node) { + return printTreeToString(node, true); + } + + public static void printCompactTree(PrintStream p, Node node) { + printCompactTree(p, null, node, 1); + } + + private static void printCompactTree(PrintStream p, Node parent, Node node, int level) { + if (node == null) { + return; + } + for (int i = 0; i < level; i++) { + p.print(" "); + } + if (parent == null) { + p.println(node.getClass().getSimpleName()); + } else { + String fieldName = null; + Field[] fields = NodeUtil.getAllFields(parent.getClass()); + try { + for (Field field : fields) { + field.setAccessible(true); + Object value = field.get(parent); + if (value == node) { + fieldName = field.getName(); + break; + } else if (value instanceof Node[]) { + int index = 0; + for (Node arrayNode : (Node[]) value) { + if (arrayNode == node) { + fieldName = field.getName() + "[" + index + "]"; + break; + } + index++; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (fieldName == null) { + fieldName = "unknownField"; + } + p.print(fieldName); + p.print(" = "); + p.println(node.getClass().getSimpleName()); + } + + for (Node child : node.getChildren()) { + printCompactTree(p, node, child, level + 1); + } + } + /** * Prints a human readable form of a tree to the given {@link PrintStream}. The * {@link TreeResolver} interface needs to be implemented to specify how the method can read the @@ -635,12 +701,12 @@ @Override public boolean isChildObject(Field f) { - return Node.class.isAssignableFrom(f.getType()); + return Node.class.isAssignableFrom(f.getType()) && f.getAnnotation(Child.class) != null; } @Override public boolean isChildArrayObject(Field f) { - return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()); + return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()) && f.getAnnotation(Children.class) != null; } @Override diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Mon May 13 17:11:31 2013 +0200 @@ -48,6 +48,7 @@ private final DeclaredType childAnnotation; private final DeclaredType childrenAnnotation; private final TypeMirror compilerDirectives; + private final TypeMirror compilerAsserts; private final List errors = new ArrayList<>(); @@ -59,6 +60,7 @@ childAnnotation = getRequired(context, Child.class); childrenAnnotation = getRequired(context, Children.class); compilerDirectives = getRequired(context, CompilerDirectives.class); + compilerAsserts = getRequired(context, CompilerAsserts.class); assumption = getRequired(context, Assumption.class); invalidAssumption = getRequired(context, InvalidAssumptionException.class); } @@ -118,4 +120,8 @@ public DeclaredType getChildrenAnnotation() { return childrenAnnotation; } + + public TypeMirror getCompilerAsserts() { + return compilerAsserts; + } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Mon May 13 17:11:31 2013 +0200 @@ -475,6 +475,19 @@ currentElement.registerAtEnd(callback); } + public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) { + if (!Utils.isVoid(type)) { + startStatement(); + type(type); + string(" "); + string(name); + string(" = "); + defaultValue(type); + end(); // statement + } + return this; + } + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { if (Utils.isVoid(type)) { startStatement(); diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon May 13 17:11:31 2013 +0200 @@ -43,6 +43,9 @@ private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; + private static final String EXECUTE_GENERIC_NAME = "executeGeneric_"; + private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize_"; + public NodeCodeGenerator(ProcessorContext context) { super(context); } @@ -243,41 +246,16 @@ return builder.getRoot(); } - private static String genClassName(NodeData node) { + private static String baseClassName(NodeData node) { String nodeid = node.getNodeId(); if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { nodeid = nodeid.substring(0, nodeid.length() - 4); } String name = Utils.firstLetterUpperCase(nodeid); - name += "GenNode"; + name += "BaseNode"; return name; } - private String generatedGenericMethodName(SpecializationData specialization) { - final String prefix = "generic"; - - if (specialization == null) { - return prefix; - } - - if (!specialization.getNode().needsRewrites(context)) { - return prefix; - } - - SpecializationData prev = null; - for (SpecializationData current : specialization.getNode().getSpecializations()) { - if (specialization == current) { - if (prev == null || prev.isUninitialized()) { - return prefix; - } else { - return prefix + current.getId(); - } - } - prev = current; - } - return prefix; - } - private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); startCallTypeSystemMethod(context, builder, node, methodName); @@ -419,15 +397,9 @@ String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (emitAssumptions) { - boolean isStatic = parent.findMethod().getModifiers().contains(STATIC); - for (String assumption : guardedSpecialization.getAssumptions()) { builder.string(andOperator); - if (isStatic) { - builder.string(THIS_NODE_LOCAL_VAR_NAME); - } else { - builder.string("this"); - } + builder.string("this"); builder.string(".").string(assumption).string(".isValid()"); andOperator = " && "; } @@ -599,6 +571,16 @@ return true; } + private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn().startNew(nodeSpecializationClassName(specialization)); + if (hasCopyConstructor) { + builder.string(thisLocalVariableName); + } + builder.end().end(); + return builder.getRoot(); + } + @Override protected void createChildren(NodeData node) { Map> childTypes = new LinkedHashMap<>(); @@ -614,15 +596,15 @@ } } - private class NodeGenFactory extends ClassElementFactory { + private class NodeBaseFactory extends ClassElementFactory { - public NodeGenFactory(ProcessorContext context) { + public NodeBaseFactory(ProcessorContext context) { super(context); } @Override protected CodeTypeElement create(NodeData node) { - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); for (NodeChildData child : node.getChildren()) { clazz.add(createChildField(child)); @@ -649,6 +631,19 @@ return clazz; } + @Override + protected void createChildren(NodeData node) { + CodeTypeElement clazz = getElement(); + + if (node.needsRewrites(context)) { + clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true)); + } + + if (node.getGenericSpecialization() != null) { + clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false)); + } + } + private void createConstructors(NodeData node, CodeTypeElement clazz) { List constructors = findUserConstructors(node.getNodeType()); if (constructors.isEmpty()) { @@ -749,6 +744,162 @@ var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); return var; } + + private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) { + TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name); + CodeTreeBuilder builder = method.createBuilder(); + + String prefix = null; + if (specialize) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end(); + builder.end(); + + emitSpecializationListeners(builder, node); + builder.defaultDeclaration(node.getGenericSpecialization().getReturnSignature().getPrimitiveType(), "result"); + if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) { + builder.defaultDeclaration(getContext().getType(boolean.class), "resultIsSet"); + } + builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); + prefix = null; + } + + addInternalValueParameters(method, node.getGenericSpecialization(), true); + + List specializations = node.getSpecializations(); + if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) { + specializations = Arrays.asList(node.getGenericSpecialization()); + } + + // group specializations for reachabiltiy + List unreachableSpecializations = new ArrayList<>(); + List filteredSpecializations = new ArrayList<>(); + if (!specialize) { + unreachableSpecializations = new ArrayList<>(); + filteredSpecializations = new ArrayList<>(); + boolean unreachable = false; + for (SpecializationData specialization : specializations) { + if (unreachable) { + unreachableSpecializations.add(specialization); + } else { + filteredSpecializations.add(specialization); + if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) { + unreachable = true; + } + } + } + } else { + unreachableSpecializations = Collections.emptyList(); + filteredSpecializations = specializations; + } + + for (SpecializationData current : filteredSpecializations) { + if (current.isUninitialized()) { + continue; + } + CodeTreeBuilder execute = new CodeTreeBuilder(builder); + + execute.tree(createGenericInvoke(builder, current, specialize)); + + if (specialize && !current.isGeneric()) { + builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); + } + + builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true)); + } + + for (SpecializationData specializationData : unreachableSpecializations) { + builder.string("// unreachable ").string(specializationData.getId()).newLine(); + } + + return method; + } + + private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + if (!current.getExceptions().isEmpty()) { + builder.startTryBlock(); + } + + CodeTree executeCall = null; + if (current.getMethod() != null) { + executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null); + } + + if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + emitEncounteredSynthetic(builder); + } else if (specialize) { + + if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + builder.startIf().string("!resultIsSet").end().startBlock(); + if (executeCall != null) { + if (current.getReturnSignature().isVoid()) { + builder.statement(executeCall); + } else { + builder.startStatement().string("result = ").tree(executeCall).end(); + } + builder.statement("resultIsSet = true"); + } else { + emitEncounteredSynthetic(builder); + } + builder.end(); + } + + if (!current.isGeneric()) { + builder.startIf().string("allowed").end().startBlock(); + } + + if (!current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + if (current.getReturnSignature().isVoid()) { + builder.statement(executeCall); + } else { + builder.startStatement().string("result = ").tree(executeCall).end(); + } + } + + builder.startStatement().startCall("super", "replace"); + builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); + builder.end().end(); + + if (current.getReturnSignature().isVoid()) { + builder.returnStatement(); + } else { + builder.startReturn().string("result").end(); + } + if (!current.isGeneric()) { + builder.end(); + } + } else { + if (executeCall == null) { + emitEncounteredSynthetic(builder); + } else { + builder.startReturn().tree(executeCall).end(); + } + } + + if (!current.getExceptions().isEmpty()) { + for (SpecializationThrowsData exception : current.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); + builder.string("// fall through").newLine(); + } + builder.end(); + } + + return builder.getRoot(); + } + + private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { + for (TemplateMethod listener : node.getSpecializationListeners()) { + builder.startStatement(); + builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); + builder.end(); // statement + } + } } private class NodeFactoryFactory extends ClassElementFactory { @@ -781,23 +932,15 @@ Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); if (node.needsFactory()) { - NodeGenFactory factory = new NodeGenFactory(context); + NodeBaseFactory factory = new NodeBaseFactory(context); add(factory, node); generatedNode = factory.getElement(); - createFactoryMethods(node, clazz, createVisibility); - if (node.needsRewrites(context)) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); - clazz.add(createSpecializeMethod(node)); } - if (node.getGenericSpecialization() != null) { - List genericMethods = createGeneratedGenericMethod(node); - for (CodeExecutableElement method : genericMethods) { - clazz.add(method); - } - } + createFactoryMethods(node, clazz, createVisibility); for (SpecializationData specialization : node.getSpecializations()) { add(new SpecializedNodeFactory(context, generatedNode), specialization); @@ -1174,125 +1317,6 @@ return method; } - private CodeExecutableElement createSpecializeMethod(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - - CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); - - boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; - - for (int i = 1; i < node.getSpecializations().size(); i++) { - SpecializationData specialization = node.getSpecializations().get(i); - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); - - CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor); - - body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true)); - } - body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); - - return method; - } - - private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startReturn().startNew(nodeSpecializationClassName(specialization)); - if (hasCopyConstructor) { - builder.string(thisLocalVariableName); - } - builder.end().end(); - return builder.getRoot(); - } - - private List createGeneratedGenericMethod(NodeData node) { - TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); - if (node.needsRewrites(context)) { - List methods = new ArrayList<>(); - - List specializations = node.getSpecializations(); - SpecializationData prev = null; - for (int i = 0; i < specializations.size(); i++) { - SpecializationData current = specializations.get(i); - SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; - if (prev == null || current.isUninitialized()) { - prev = current; - continue; - } else { - String methodName = generatedGenericMethodName(current); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - - emitGeneratedGenericSpecialization(method.createBuilder(), current, next); - - methods.add(method); - } - prev = current; - } - - return methods; - } else { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); - method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); - addInternalValueParameters(method, node.getGenericSpecialization(), true); - emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); - return Arrays.asList(method); - } - } - - private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { - CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder); - emitInvokeDoMethod(invokeMethodBuilder, current, 0); - CodeTree invokeMethod = invokeMethodBuilder.getRoot(); - - if (next != null) { - CodeTreeBuilder nextBuilder = builder.create(); - - nextBuilder.startReturn().startCall(generatedGenericMethodName(next)); - nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME); - addInternalValueParameterNames(nextBuilder, next, next, null, true, true); - nextBuilder.end().end(); - - invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true); - } - - builder.tree(invokeMethod); - - if (next != null) { - builder.end(); - } - } - - private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { - if (!specialization.getExceptions().isEmpty()) { - builder.startTryBlock(); - } - - if (specialization.getMethod() == null) { - emitEncounteredSynthetic(builder); - } else { - builder.startReturn(); - builder.tree(createTemplateMethodCall(builder, null, specialization.getNode().getGenericSpecialization(), specialization, null)); - builder.end(); // return - } - - if (!specialization.getExceptions().isEmpty()) { - for (SpecializationThrowsData exception : specialization.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); - - builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); - builder.string(THIS_NODE_LOCAL_VAR_NAME); - addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true); - builder.end().end(); - } - builder.end(); - } - } - } private class SpecializedNodeFactory extends ClassElementFactory { @@ -1342,10 +1366,6 @@ clazz.remove(executeMethod); } } - - if (specialization.hasRewrite(getContext())) { - buildSpecializeAndExecute(clazz, specialization); - } } private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { @@ -1440,8 +1460,7 @@ List executeParameters = new ArrayList<>(); for (ActualParameter sourceParameter : executable.getParameters()) { - NodeChildData field = specialization.getNode().findChild(sourceParameter.getSpecification().getName()); - if (field == null) { + if (!sourceParameter.getSpecification().isSignature()) { continue; } @@ -1474,14 +1493,14 @@ builder.string("// ignore").newLine(); } else { builder.startReturn(); - builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); + builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()"))); builder.end(); } builder.end(); if (!returnVoid) { builder.startReturn(); - builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value"))); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value"))); builder.end(); } } else { @@ -1489,7 +1508,7 @@ builder.statement(primaryExecuteCall); } else { builder.startReturn(); - builder.tree(createExpectType(node, castedType, primaryExecuteCall)); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall)); builder.end(); } } @@ -1497,21 +1516,24 @@ return builder.getRoot(); } - private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) { - if (castedType == null) { + private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { + boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); + return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); + } + + private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { + if (targetType == null) { return value; - } else if (castedType.getType().isVoid()) { - return value; - } else if (castedType.getType().isGeneric()) { + } else if (!sourceType.needsCastTo(getContext(), targetType)) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); String targetMethodName; - if (castedType.hasUnexpectedValue(getContext())) { - targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()); + if (expect) { + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); } else { - targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()); + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); } startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); @@ -1520,24 +1542,6 @@ return builder.getRoot(); } - private CodeTree createExpectType(NodeData node, TypeData castedType, CodeTree value) { - if (castedType == null) { - return value; - } else if (castedType.isVoid()) { - return value; - } else if (castedType.isGeneric()) { - return value; - } - - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - String targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType); - startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); - - builder.tree(value); - builder.end().end(); - return builder.getRoot(); - } - private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { @@ -1547,15 +1551,15 @@ builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); CodeTree executeNode; - if (specialization.isUninitialized()) { - builder.tree(createSpecializeCall(builder, specialization)); - } executeNode = createExecute(builder, executable, specialization); SpecializationData next = specialization.findNextSpecialization(); CodeTree returnSpecialized = null; if (next != null) { - returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null); + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); + returnBuilder.tree(createDeoptimize(builder)); + returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null)); + returnSpecialized = returnBuilder.getRoot(); } builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); @@ -1570,28 +1574,6 @@ return builder.getRoot(); } - private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { - NodeData node = specialization.getNode(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - emitSpecializationListeners(builder, node); - - builder.startStatement(); - builder.startCall("replace"); - if (node.needsRewrites(getContext())) { - builder.startCall(factoryClassName(node), "specialize"); - builder.string("this"); - builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addInternalValueParameterNames(builder, specialization, specialization, null, true, true); - builder.end(); // call replace, call specialize - } else { - builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); - } - builder.end().end(); - emitSpecializationListeners(builder, node); - return builder.getRoot(); - } - private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1607,23 +1589,14 @@ CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { - String genericMethodName = generatedGenericMethodName(null); - returnBuilder.startCall(factoryClassName(node), genericMethodName); - returnBuilder.string("this"); + returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); + returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { emitEncounteredSynthetic(builder); } else if (specialization.isGeneric()) { - String genericMethodName; - if (!specialization.isUseSpecializationsForGeneric()) { - genericMethodName = generatedGenericMethodName(specialization); - } else { - genericMethodName = generatedGenericMethodName(null); - } - - returnBuilder.startCall(factoryClassName(node), genericMethodName); - returnBuilder.string("this"); + returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else { @@ -1649,13 +1622,14 @@ if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null)); + builder.tree(createDeoptimize(builder)); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null)); } builder.end(); } if (!specialization.getAssumptions().isEmpty()) { builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); - builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null)); + builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null)); builder.end(); } @@ -1670,21 +1644,24 @@ for (ActualParameter targetParameter : targetParameters) { NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName()); - if (field == null) { + if (!targetParameter.getSpecification().isSignature()) { continue; } + TypeData targetType = targetParameter.getTypeSystemType(); - - ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType); + ExecutableTypeData targetExecutable = null; + if (field != null) { + targetExecutable = field.findExecutableType(getContext(), targetType); + } ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); String targetVariableName = valueName(targetParameter); CodeTree executionExpression = null; - if (cast || sourceParameter != null) { + if ((sourceParameter != null && cast) || sourceParameter != null) { TypeData sourceType = sourceParameter.getTypeSystemType(); - if (!sourceType.needsCastTo(getContext(), targetType)) { - if (field.isShortCircuit() && sourceParameter != null) { + if (targetExecutable == null || !sourceType.needsCastTo(getContext(), targetType)) { + if (field != null && field.isShortCircuit() && sourceParameter != null) { builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); } builder.startStatement(); @@ -1692,8 +1669,10 @@ builder.string(valueName(targetParameter)).string(" = "); builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); builder.end(); + continue; } else { - executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); + CodeTree valueTree = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); + executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, valueTree); } } else if (sourceParameter == null) { executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); @@ -1712,14 +1691,6 @@ return builder.getRoot(); } - private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { - for (TemplateMethod listener : node.getSpecializationListeners()) { - builder.startStatement(); - builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); - builder.end(); // statement - } - } - private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1749,7 +1720,7 @@ } builder.string(" = "); if (cast) { - builder.tree(createExpectType(specialization.getNode(), param.getTypeSystemType(), body)); + builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body)); } else { builder.tree(body); } @@ -1761,8 +1732,9 @@ ActualParameter genericParameter = generic.findParameter(param.getLocalName()); List genericParameters = generic.getParametersAfter(genericParameter); + builder.tree(createDeoptimize(builder)); builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); - builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param)); + builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param)); builder.end(); // catch block } @@ -1878,71 +1850,24 @@ return builder.getRoot(); } - private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) { + private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) { + + SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization(); CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); - specializeCall.startCall("specializeAndExecute"); + specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); - addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), nextSpecialization.getNode().getGenericSpecialization(), - exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); + addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn(); - builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot())); + builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot())); builder.end(); return builder.getRoot(); } - private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) { - NodeData node = specialization.getNode(); - TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType(); - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true); - clazz.add(method); - - CodeTreeBuilder builder = method.createBuilder(); - - builder.tree(createDeoptimize(builder)); - emitSpecializationListeners(builder, specialization.getNode()); - - builder.startStatement(); - builder.startCall("replace"); - builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true); - builder.end(); - builder.end(); // call replace - builder.end(); // statement - - String generatedMethodName; - if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { - generatedMethodName = generatedGenericMethodName(null); - } else { - generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); - } - ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); - - CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); - genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); - genericExecute.string("this"); - addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true); - genericExecute.end(); // call generated generic - - CodeTree genericInvocation = genericExecute.getRoot(); - - if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) { - builder.statement(genericInvocation); - - if (!Utils.isVoid(builder.findMethod().asType())) { - builder.startReturn().defaultValue(returnType.getPrimitiveType()).end(); - } - } else { - builder.startReturn().tree(genericInvocation).end(); - } - } - } } diff -r 57113d21ce36 -r f9a65a0e626b graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java Mon May 13 16:46:39 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java Mon May 13 17:11:31 2013 +0200 @@ -49,7 +49,7 @@ return result.toString(); } - protected void executeSL(String[] input, String[] expectedOutput, boolean useConsole) { + protected static void executeSL(String[] input, String[] expectedOutput, boolean useConsole) { InputStream in = new ByteArrayInputStream(concat(input).getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); diff -r 57113d21ce36 -r f9a65a0e626b make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Mon May 13 16:46:39 2013 +0200 +++ b/make/bsd/makefiles/buildtree.make Mon May 13 17:11:31 2013 +0200 @@ -243,7 +243,9 @@ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os/posix/vm)"; \ + echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \ + echo "$(call gamma-path,altsrc,gpu/ptx) \\"; \ + echo "$(call gamma-path,commonsrc,gpu/ptx)"; \ echo; \ echo "Src_Dirs_I = \\"; \ echo "$(call gamma-path,altsrc,share/vm/prims) \\"; \ @@ -259,7 +261,9 @@ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os/posix/vm)"; \ + echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \ + echo "$(call gamma-path,altsrc,gpu) \\"; \ + echo "$(call gamma-path,commonsrc,gpu)"; \ [ -n "$(CFLAGS_BROWSE)" ] && \ echo && echo "CFLAGS_BROWSE = $(CFLAGS_BROWSE)"; \ [ -n "$(HOTSPOT_EXTRA_SYSDEFS)" ] && \ diff -r 57113d21ce36 -r f9a65a0e626b make/bsd/makefiles/launcher.make --- a/make/bsd/makefiles/launcher.make Mon May 13 16:46:39 2013 +0200 +++ b/make/bsd/makefiles/launcher.make Mon May 13 17:11:31 2013 +0200 @@ -67,7 +67,7 @@ # framework libraries. ifeq ($(OS_VENDOR),Darwin) - LFLAGS_LAUNCHER += -framework CoreFoundation + LFLAGS_LAUNCHER += -framework CoreFoundation -framework ApplicationServices endif LIBS_LAUNCHER += -l$(JVM) $(LIBS) diff -r 57113d21ce36 -r f9a65a0e626b make/bsd/makefiles/vm.make --- a/make/bsd/makefiles/vm.make Mon May 13 16:46:39 2013 +0200 +++ b/make/bsd/makefiles/vm.make Mon May 13 17:11:31 2013 +0200 @@ -128,6 +128,10 @@ LIBS += -lm -pthread +ifeq ($(OS_VENDOR),Darwin) + LIBS += -framework ApplicationServices -framework IOKit +endif + # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM @@ -157,6 +161,7 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm +SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx ifndef JAVASE_EMBEDDED SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \ @@ -179,7 +184,9 @@ SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/share/vm/graal) +GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/gpu/ptx) GRAAL_PATHS += $(HS_COMMON_SRC)/share/vm/graal +GRAAL_PATHS += $(HS_COMMON_SRC)/gpu/ptx # Include dirs per type. Src_Dirs/CORE := $(CORE_PATHS) diff -r 57113d21ce36 -r f9a65a0e626b make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Mon May 13 16:46:39 2013 +0200 +++ b/make/linux/makefiles/buildtree.make Mon May 13 17:11:31 2013 +0200 @@ -238,7 +238,9 @@ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os/posix/vm)"; \ + echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \ + echo "$(call gamma-path,altsrc,gpu/ptx) \\"; \ + echo "$(call gamma-path,commonsrc,gpu/ptx)"; \ echo; \ echo "Src_Dirs_I = \\"; \ echo "$(call gamma-path,altsrc,share/vm/prims) \\"; \ @@ -253,8 +255,9 @@ echo "$(call gamma-path,commonsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os/$(OS_FAMILY)/vm) \\"; \ echo "$(call gamma-path,commonsrc,os/$(OS_FAMILY)/vm) \\"; \ - echo "$(call gamma-path,altsrc,os/posix/vm) \\"; \ - echo "$(call gamma-path,commonsrc,os/posix/vm)"; \ + echo "$(call gamma-path,commonsrc,os/posix/vm) \\"; \ + echo "$(call gamma-path,altsrc,gpu) \\"; \ + echo "$(call gamma-path,commonsrc,gpu)"; \ [ -n "$(CFLAGS_BROWSE)" ] && \ echo && echo "CFLAGS_BROWSE = $(CFLAGS_BROWSE)"; \ [ -n "$(ENABLE_FULL_DEBUG_SYMBOLS)" ] && \ diff -r 57113d21ce36 -r f9a65a0e626b make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Mon May 13 16:46:39 2013 +0200 +++ b/make/linux/makefiles/vm.make Mon May 13 17:11:31 2013 +0200 @@ -157,6 +157,7 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm +SOURCE_PATHS+=$(HS_COMMON_SRC)/gpu/ptx ifndef JAVASE_EMBEDDED ifneq (${ARCH},arm) @@ -181,7 +182,9 @@ SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/share/vm/graal) +GRAAL_PATHS += $(call altsrc,$(HS_COMMON_SRC)/gpu/ptx) GRAAL_PATHS += $(HS_COMMON_SRC)/share/vm/graal +GRAAL_PATHS += $(HS_COMMON_SRC)/gpu/ptx # Include dirs per type. Src_Dirs/CORE := $(CORE_PATHS) diff -r 57113d21ce36 -r f9a65a0e626b make/windows/makefiles/projectcreator.make --- a/make/windows/makefiles/projectcreator.make Mon May 13 16:46:39 2013 +0200 +++ b/make/windows/makefiles/projectcreator.make Mon May 13 17:11:31 2013 +0200 @@ -55,6 +55,7 @@ -relativeInclude src\os\windows\vm \ -relativeInclude src\os_cpu\windows_$(Platform_arch)\vm \ -relativeInclude src\cpu\$(Platform_arch)\vm \ + -relativeInclude src\gpu \ -absoluteInclude $(HOTSPOTBUILDSPACE)/%f/generated \ -relativeSrcInclude src \ -absoluteSrcInclude $(HOTSPOTBUILDSPACE) \ diff -r 57113d21ce36 -r f9a65a0e626b mx/JUnitWrapper.java --- a/mx/JUnitWrapper.java Mon May 13 16:46:39 2013 +0200 +++ b/mx/JUnitWrapper.java Mon May 13 17:11:31 2013 +0200 @@ -67,7 +67,11 @@ } String[] strargs = tests.toArray(new String[tests.size()]); - System.out.printf("executing junit tests now... (%d test classes)\n", strargs.length); + if (strargs.length == 1) { + System.out.printf("executing junit test now... (%s)\n", strargs[0]); + } else { + System.out.printf("executing junit tests now... (%d test classes)\n", strargs.length); + } JUnitCore.main(strargs); } } diff -r 57113d21ce36 -r f9a65a0e626b mx/commands.py --- a/mx/commands.py Mon May 13 16:46:39 2013 +0200 +++ b/mx/commands.py Mon May 13 17:11:31 2013 +0200 @@ -749,7 +749,7 @@ excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys() excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys() - includes = ['com.oracle.graal.*', 'com.oracle.max.*'] + includes = ['com.oracle.graal.*'] agentOptions = { 'append' : 'true' if _jacoco == 'append' else 'false', 'bootclasspath' : 'true', @@ -788,6 +788,8 @@ classes = [] for p in mx.projects(): + if mx.java().javaCompliance < p.javaCompliance: + continue classes += _find_classes_with_annotations(p, None, annotations).keys() if len(pos) != 0: @@ -795,7 +797,7 @@ if len(neg) != 0: classes = [c for c in classes if not containsAny(c, neg)] - projectscp = mx.classpath([pcp.name for pcp in mx.projects()]) + projectscp = mx.classpath([pcp.name for pcp in mx.projects() if pcp.javaCompliance <= mx.java().javaCompliance]) if len(classes) != 0: f_testfile = open(testfile, 'w') @@ -829,30 +831,47 @@ if os.environ.get('MX_TESTFILE') is None: os.remove(testfile) -def unittest(args): - """run the JUnit tests (all testcases) +_unittestHelpSuffix = """ If filters are supplied, only tests whose fully qualified name - include a filter as a substring are run. Negative filters are - those with a '-' prefix. VM args should have a @ prefix.""" + includes a filter as a substring are run. Negative filters are + those with a '-' prefix. + + Options with a '@' prefix are passed to the VM. + + For example, this command line: + + mx unittest BC_aload @-G:Dump= @-G:MethodFilter=BC_aload.* @-G:+PrintCFG + + will run all JUnit test classes that contain 'BC_aload' in their + fully qualified name and will pass these options to the VM: + + -G:Dump= -G:MethodFilter=BC_aload.* -G:+PrintCFG + + To get around command line length limitations on some OSes, the + JUnit class names to be executed are written to a file that a + custom JUnit wrapper reads and passes onto JUnit proper. The + MX_TESTFILE environment variable can be set to specify a + file which will not be deleted once the unittests are done + (unlike the temporary file otherwise used). + + As with all other commands, using the global '-v' before 'unittest' + command will cause mx to show the complete shell command line + it uses to run the VM. +""" + +def unittest(args): + """run the JUnit tests (all testcases){0}""" _unittest(args, ['@Test', '@LongTest']) def shortunittest(args): - """run the JUnit tests (short testcases only) - - If filters are supplied, only tests whose fully qualified name - include a filter as a substring are run. Negative filters are - those with a '-' prefix. VM args should have a @ prefix.""" + """run the JUnit tests (short testcases only){0}""" _unittest(args, ['@Test']) def longunittest(args): - """run the JUnit tests (long testcases only) - - If filters are supplied, only tests whose fully qualified name - include a filter as a substring are run. Negative filters are - those with a '-' prefix. VM args should have a @ prefix.""" + """run the JUnit tests (long testcases only){0}""" _unittest(args, ['@LongTest']) @@ -1341,9 +1360,9 @@ 'gate' : [gate, '[-options]'], 'gv' : [gv, ''], 'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'], - 'unittest' : [unittest, '[filters...]'], - 'longunittest' : [longunittest, '[filters...]'], - 'shortunittest' : [shortunittest, '[filters...]'], + 'unittest' : [unittest, '[filters...|@VM options]', _unittestHelpSuffix], + 'longunittest' : [longunittest, '[filters...|@VM options]', _unittestHelpSuffix], + 'shortunittest' : [shortunittest, '[filters...|@VM options]', _unittestHelpSuffix], 'jacocoreport' : [jacocoreport, '[output directory]'], 'site' : [site, '[-options]'], 'vm': [vm, '[-options] class [args...]'], diff -r 57113d21ce36 -r f9a65a0e626b mx/projects --- a/mx/projects Mon May 13 16:46:39 2013 +0200 +++ b/mx/projects Mon May 13 17:11:31 2013 +0200 @@ -295,7 +295,7 @@ # graal.compiler.ptx project@com.oracle.graal.compiler.ptx@subDir=graal project@com.oracle.graal.compiler.ptx@sourceDirs=src -project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.ptx +project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.lir.ptx,com.oracle.graal.hotspot project@com.oracle.graal.compiler.ptx@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.ptx@javaCompliance=1.7 diff -r 57113d21ce36 -r f9a65a0e626b mx/sanitycheck.py --- a/mx/sanitycheck.py Mon May 13 16:46:39 2013 +0200 +++ b/mx/sanitycheck.py Mon May 13 17:11:31 2013 +0200 @@ -47,7 +47,8 @@ } dacapoScalaSanityWarmup = { - 'actors': [0, 0, 2, 8, 10], +# (tw) actors sometimes fails verification; hardly reproducible + 'actors': [0, 0, 0, 0, 0], # (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault. 'apparat': [0, 0, 0, 0, 0], 'factorie': [0, 0, 2, 5, 5], diff -r 57113d21ce36 -r f9a65a0e626b src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1177 +0,0 @@ -/* - * Copyright (c) 1999, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "graal/graalRuntime.hpp" -#include "interpreter/interpreter.hpp" -#include "nativeInst_x86.hpp" -#include "oops/compiledICHolder.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "register_x86.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/signature.hpp" -#include "runtime/vframeArray.hpp" -#include "vmreg_x86.inline.hpp" - -static void restore_live_registers(GraalStubAssembler* sasm, bool restore_fpu_registers = true); - -// Implementation of GraalStubAssembler - -int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, int args_size) { - // setup registers - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); // is callee-saved register (Visual C++ calling conventions) - assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different"); - assert(oop_result1 != thread && metadata_result != thread, "registers must be different"); - assert(args_size >= 0, "illegal args_size"); - -#ifdef _LP64 - mov(c_rarg0, thread); - set_num_rt_args(0); // Nothing on stack -#else - set_num_rt_args(1 + args_size); - - // push java thread (becomes first argument of C function) - get_thread(thread); - push(thread); -#endif // _LP64 - - int call_offset; - set_last_Java_frame(thread, rsp, noreg, NULL); - - // do the call - call(RuntimeAddress(entry)); - call_offset = offset(); - // verify callee-saved register -#ifdef ASSERT - guarantee(thread != rax, "change this code"); - push(rax); - { Label L; - get_thread(rax); - cmpptr(thread, rax); - jcc(Assembler::equal, L); - int3(); - stop("GraalStubAssembler::call_RT: rdi not callee saved?"); - bind(L); - } - pop(rax); -#endif - reset_last_Java_frame(thread, true, false); - - // discard thread and arguments - NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord)); - - // check for pending exceptions - { Label L; - cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); - jcc(Assembler::equal, L); - // exception pending => remove activation and forward to exception handler - movptr(rax, Address(thread, Thread::pending_exception_offset())); - // make sure that the vm_results are cleared - if (oop_result1->is_valid()) { - movptr(Address(thread, JavaThread::vm_result_offset()), NULL_WORD); - } - if (metadata_result->is_valid()) { - movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD); - } - // (thomaswue) Deoptimize in case of an exception. - restore_live_registers(this, false); - movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); - leave(); - movl(Address(thread, ThreadShadow::pending_deoptimization_offset()), Deoptimization::make_trap_request(Deoptimization::Reason_constraint, Deoptimization::Action_reinterpret)); - jump(RuntimeAddress(SharedRuntime::deopt_blob()->uncommon_trap())); - bind(L); - } - // get oop results if there are any and reset the values in the thread - if (oop_result1->is_valid()) { - get_vm_result(oop_result1, thread); - } - if (metadata_result->is_valid()) { - get_vm_result_2(metadata_result, thread); - } - return call_offset; -} - - -int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { -#ifdef _LP64 - mov(c_rarg1, arg1); -#else - push(arg1); -#endif // _LP64 - return call_RT(oop_result1, metadata_result, entry, 1); -} - - -int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { -#ifdef _LP64 - if (c_rarg1 == arg2) { - if (c_rarg2 == arg1) { - xchgq(arg1, arg2); - } else { - mov(c_rarg2, arg2); - mov(c_rarg1, arg1); - } - } else { - mov(c_rarg1, arg1); - mov(c_rarg2, arg2); - } -#else - push(arg2); - push(arg1); -#endif // _LP64 - return call_RT(oop_result1, metadata_result, entry, 2); -} - - -int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { -#ifdef _LP64 - // if there is any conflict use the stack - if (arg1 == c_rarg2 || arg1 == c_rarg3 || - arg2 == c_rarg1 || arg1 == c_rarg3 || - arg3 == c_rarg1 || arg1 == c_rarg2) { - push(arg3); - push(arg2); - push(arg1); - pop(c_rarg1); - pop(c_rarg2); - pop(c_rarg3); - } else { - mov(c_rarg1, arg1); - mov(c_rarg2, arg2); - mov(c_rarg3, arg3); - } -#else - push(arg3); - push(arg2); - push(arg1); -#endif // _LP64 - return call_RT(oop_result1, metadata_result, entry, 3); -} - -int GraalStubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3, Register arg4) { -#ifdef _LP64 - #ifdef _WIN64 - // on windows we only have the registers c_rarg0 to c_rarg3 for transferring parameters -> remaining parameters are on the stack - if (arg1 == c_rarg2 || arg1 == c_rarg3 || - arg2 == c_rarg1 || arg2 == c_rarg3 || - arg3 == c_rarg1 || arg3 == c_rarg2 || - arg4 == c_rarg1 || arg4 == c_rarg2) { - push(arg4); - push(arg3); - push(arg2); - push(arg1); - pop(c_rarg1); - pop(c_rarg2); - pop(c_rarg3); - } else { - mov(c_rarg1, arg1); - mov(c_rarg2, arg2); - mov(c_rarg3, arg3); - push(arg4); - } - #else - // if there is any conflict use the stack - if (arg1 == c_rarg2 || arg1 == c_rarg3 || arg1 == c_rarg4 || - arg2 == c_rarg1 || arg2 == c_rarg3 || arg2 == c_rarg4 || - arg3 == c_rarg1 || arg3 == c_rarg2 || arg3 == c_rarg4 || - arg4 == c_rarg1 || arg4 == c_rarg2 || arg4 == c_rarg3) { - push(arg4); - push(arg3); - push(arg2); - push(arg1); - pop(c_rarg1); - pop(c_rarg2); - pop(c_rarg3); - pop(c_rarg4); - } else { - mov(c_rarg1, arg1); - mov(c_rarg2, arg2); - mov(c_rarg3, arg3); - mov(c_rarg4, arg4); - } - #endif -#else - push(arg4); - push(arg3); - push(arg2); - push(arg1); -#endif // _LP64 - return call_RT(oop_result1, metadata_result, entry, 4); -} - -// Implementation of GraalStubFrame - -class GraalStubFrame: public StackObj { - private: - GraalStubAssembler* _sasm; - - public: - GraalStubFrame(GraalStubAssembler* sasm, const char* name, bool must_gc_arguments); - ~GraalStubFrame(); -}; - - -#define __ _sasm-> - -GraalStubFrame::GraalStubFrame(GraalStubAssembler* sasm, const char* name, bool must_gc_arguments) { - _sasm = sasm; - __ set_info(name, must_gc_arguments); - __ enter(); -} - -GraalStubFrame::~GraalStubFrame() { - __ leave(); - __ ret(0); -} - -#undef __ - - -// Implementation of GraalRuntime - -const int float_regs_as_doubles_size_in_slots = FloatRegisterImpl::number_of_registers * 2; -const int xmm_regs_as_doubles_size_in_slots = XMMRegisterImpl::number_of_registers * 2; - -// Stack layout for saving/restoring all the registers needed during a runtime -// call (this includes deoptimization) -// Note: note that users of this frame may well have arguments to some runtime -// while these values are on the stack. These positions neglect those arguments -// but the code in save_live_registers will take the argument count into -// account. -// -#ifdef _LP64 - #define SLOT2(x) x, - #define SLOT_PER_WORD 2 -#else - #define SLOT2(x) - #define SLOT_PER_WORD 1 -#endif // _LP64 - -enum reg_save_layout { - // 64bit needs to keep stack 16 byte aligned. So we add some alignment dummies to make that - // happen and will assert if the stack size we create is misaligned -#ifdef _LP64 - align_dummy_0, align_dummy_1, -#endif // _LP64 -#ifdef _WIN64 - // Windows always allocates space for it's argument registers (see - // frame::arg_reg_save_area_bytes). - arg_reg_save_1, arg_reg_save_1H, // 0, 4 - arg_reg_save_2, arg_reg_save_2H, // 8, 12 - arg_reg_save_3, arg_reg_save_3H, // 16, 20 - arg_reg_save_4, arg_reg_save_4H, // 24, 28 -#endif // _WIN64 - xmm_regs_as_doubles_off, // 32 - float_regs_as_doubles_off = xmm_regs_as_doubles_off + xmm_regs_as_doubles_size_in_slots, // 160 - fpu_state_off = float_regs_as_doubles_off + float_regs_as_doubles_size_in_slots, // 224 - // fpu_state_end_off is exclusive - fpu_state_end_off = fpu_state_off + (FPUStateSizeInWords / SLOT_PER_WORD), // 352 - marker = fpu_state_end_off, SLOT2(markerH) // 352, 356 - extra_space_offset, // 360 -#ifdef _LP64 - r15_off = extra_space_offset, r15H_off, // 360, 364 - r14_off, r14H_off, // 368, 372 - r13_off, r13H_off, // 376, 380 - r12_off, r12H_off, // 384, 388 - r11_off, r11H_off, // 392, 396 - r10_off, r10H_off, // 400, 404 - r9_off, r9H_off, // 408, 412 - r8_off, r8H_off, // 416, 420 - rdi_off, rdiH_off, // 424, 428 -#else - rdi_off = extra_space_offset, -#endif // _LP64 - rsi_off, SLOT2(rsiH_off) // 432, 436 - rbp_off, SLOT2(rbpH_off) // 440, 444 - rsp_off, SLOT2(rspH_off) // 448, 452 - rbx_off, SLOT2(rbxH_off) // 456, 460 - rdx_off, SLOT2(rdxH_off) // 464, 468 - rcx_off, SLOT2(rcxH_off) // 472, 476 - rax_off, SLOT2(raxH_off) // 480, 484 - saved_rbp_off, SLOT2(saved_rbpH_off) // 488, 492 - return_off, SLOT2(returnH_off) // 496, 500 - reg_save_frame_size // As noted: neglects any parameters to runtime // 504 -}; - -// Save registers which might be killed by calls into the runtime. -// Tries to smart about FP registers. In particular we separate -// saving and describing the FPU registers for deoptimization since we -// have to save the FPU registers twice if we describe them and on P4 -// saving FPU registers which don't contain anything appears -// expensive. The deopt blob is the only thing which needs to -// describe FPU registers. In all other cases it should be sufficient -// to simply save their current value. - -static OopMap* generate_oop_map(GraalStubAssembler* sasm, int num_rt_args, - bool save_fpu_registers = true) { - - // In 64bit all the args are in regs so there are no additional stack slots - LP64_ONLY(num_rt_args = 0); - LP64_ONLY(assert((reg_save_frame_size * VMRegImpl::stack_slot_size) % 16 == 0, "must be 16 byte aligned");) - int frame_size_in_slots = reg_save_frame_size + num_rt_args; // args + thread - sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word ); - - // record saved value locations in an OopMap - // locations are offsets from sp after runtime call; num_rt_args is number of arguments in call, including thread - OopMap* map = new OopMap(frame_size_in_slots, 0); - map->set_callee_saved(VMRegImpl::stack2reg(rax_off + num_rt_args), rax->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rcx_off + num_rt_args), rcx->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rdx_off + num_rt_args), rdx->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rbp_off + num_rt_args), rbp->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg()); -#ifdef _LP64 - map->set_callee_saved(VMRegImpl::stack2reg(r8_off + num_rt_args), r8->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r9_off + num_rt_args), r9->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r10_off + num_rt_args), r10->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r11_off + num_rt_args), r11->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r12_off + num_rt_args), r12->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r13_off + num_rt_args), r13->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r14_off + num_rt_args), r14->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg(r15_off + num_rt_args), r15->as_VMReg()); - - // This is stupid but needed. - map->set_callee_saved(VMRegImpl::stack2reg(raxH_off + num_rt_args), rax->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rcxH_off + num_rt_args), rcx->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rdxH_off + num_rt_args), rdx->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rbxH_off + num_rt_args), rbx->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rbpH_off + num_rt_args), rbp->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rsiH_off + num_rt_args), rsi->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(rdiH_off + num_rt_args), rdi->as_VMReg()->next()); - - map->set_callee_saved(VMRegImpl::stack2reg(r8H_off + num_rt_args), r8->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r9H_off + num_rt_args), r9->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r10H_off + num_rt_args), r10->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r11H_off + num_rt_args), r11->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r12H_off + num_rt_args), r12->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r13H_off + num_rt_args), r13->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r14H_off + num_rt_args), r14->as_VMReg()->next()); - map->set_callee_saved(VMRegImpl::stack2reg(r15H_off + num_rt_args), r15->as_VMReg()->next()); -#endif // _LP64 - - if (save_fpu_registers) { - if (UseSSE < 2) { - int fpu_off = float_regs_as_doubles_off; - for (int n = 0; n < FloatRegisterImpl::number_of_registers; n++) { - VMReg fpu_name_0 = as_FloatRegister(n)->as_VMReg(); - map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + num_rt_args), fpu_name_0); - // %%% This is really a waste but we'll keep things as they were for now - if (true) { - map->set_callee_saved(VMRegImpl::stack2reg(fpu_off + 1 + num_rt_args), fpu_name_0->next()); - } - fpu_off += 2; - } - assert(fpu_off == fpu_state_off, "incorrect number of fpu stack slots"); - } - - if (UseSSE >= 2) { - int xmm_off = xmm_regs_as_doubles_off; - for (int n = 0; n < XMMRegisterImpl::number_of_registers; n++) { - VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg(); - map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + num_rt_args), xmm_name_0); - // %%% This is really a waste but we'll keep things as they were for now - if (true) { - map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + 1 + num_rt_args), xmm_name_0->next()); - } - xmm_off += 2; - } - assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers"); - - } else if (UseSSE == 1) { - int xmm_off = xmm_regs_as_doubles_off; - for (int n = 0; n < XMMRegisterImpl::number_of_registers; n++) { - VMReg xmm_name_0 = as_XMMRegister(n)->as_VMReg(); - map->set_callee_saved(VMRegImpl::stack2reg(xmm_off + num_rt_args), xmm_name_0); - xmm_off += 2; - } - assert(xmm_off == float_regs_as_doubles_off, "incorrect number of xmm registers"); - } - } - - return map; -} - -#define __ sasm-> - -static OopMap* save_live_registers(GraalStubAssembler* sasm, int num_rt_args, - bool save_fpu_registers = true) { - __ block_comment("save_live_registers"); - - __ pusha(); // integer registers - - // assert(float_regs_as_doubles_off % 2 == 0, "misaligned offset"); - // assert(xmm_regs_as_doubles_off % 2 == 0, "misaligned offset"); - - __ subptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); - -#ifdef ASSERT - __ movptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef); -#endif - - if (save_fpu_registers) { - if (UseSSE < 2) { - // save FPU stack - __ fnsave(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - __ fwait(); - -#ifdef ASSERT - Label ok; - __ cmpw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::fpu_cntrl_wrd_std()); - __ jccb(Assembler::equal, ok); - __ stop("corrupted control word detected"); - __ bind(ok); -#endif - - // Reset the control word to guard against exceptions being unmasked - // since fstp_d can cause FPU stack underflow exceptions. Write it - // into the on stack copy and then reload that to make sure that the - // current and future values are correct. - __ movw(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size), StubRoutines::fpu_cntrl_wrd_std()); - __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - - // Save the FPU registers in de-opt-able form - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 0)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 8)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48)); - __ fstp_d(Address(rsp, float_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56)); - } - - if (UseSSE >= 2) { - // save XMM registers - // XMM registers can contain float or double values, but this is not known here, - // so always save them as doubles. - // note that float values are _not_ converted automatically, so for float values - // the second word contains only garbage data. - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 0), xmm0); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 8), xmm1); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16), xmm2); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24), xmm3); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32), xmm4); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40), xmm5); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48), xmm6); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56), xmm7); -#ifdef _LP64 - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 64), xmm8); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 72), xmm9); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 80), xmm10); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 88), xmm11); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 96), xmm12); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 104), xmm13); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 112), xmm14); - __ movdbl(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 120), xmm15); -#endif // _LP64 - } else if (UseSSE == 1) { - // save XMM registers as float because double not supported without SSE2 - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 0), xmm0); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 8), xmm1); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16), xmm2); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24), xmm3); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32), xmm4); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40), xmm5); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48), xmm6); - __ movflt(Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56), xmm7); - } - } - - // FPU stack must be empty now - __ verify_FPU(0, "save_live_registers"); - - return generate_oop_map(sasm, num_rt_args, save_fpu_registers); -} - - -static void restore_fpu(GraalStubAssembler* sasm, bool restore_fpu_registers = true) { - if (restore_fpu_registers) { - if (UseSSE >= 2) { - // restore XMM registers - __ movdbl(xmm0, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 0)); - __ movdbl(xmm1, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 8)); - __ movdbl(xmm2, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16)); - __ movdbl(xmm3, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24)); - __ movdbl(xmm4, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32)); - __ movdbl(xmm5, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40)); - __ movdbl(xmm6, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48)); - __ movdbl(xmm7, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56)); -#ifdef _LP64 - __ movdbl(xmm8, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 64)); - __ movdbl(xmm9, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 72)); - __ movdbl(xmm10, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 80)); - __ movdbl(xmm11, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 88)); - __ movdbl(xmm12, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 96)); - __ movdbl(xmm13, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 104)); - __ movdbl(xmm14, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 112)); - __ movdbl(xmm15, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 120)); -#endif // _LP64 - } else if (UseSSE == 1) { - // restore XMM registers - __ movflt(xmm0, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 0)); - __ movflt(xmm1, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 8)); - __ movflt(xmm2, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 16)); - __ movflt(xmm3, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 24)); - __ movflt(xmm4, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 32)); - __ movflt(xmm5, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 40)); - __ movflt(xmm6, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 48)); - __ movflt(xmm7, Address(rsp, xmm_regs_as_doubles_off * VMRegImpl::stack_slot_size + 56)); - } - - if (UseSSE < 2) { - __ frstor(Address(rsp, fpu_state_off * VMRegImpl::stack_slot_size)); - } else { - // check that FPU stack is really empty - __ verify_FPU(0, "restore_live_registers"); - } - - } else { - // check that FPU stack is really empty - __ verify_FPU(0, "restore_live_registers"); - } - -#ifdef ASSERT - { - Label ok; - __ cmpptr(Address(rsp, marker * VMRegImpl::stack_slot_size), (int32_t)0xfeedbeef); - __ jcc(Assembler::equal, ok); - __ stop("bad offsets in frame"); - __ bind(ok); - } -#endif // ASSERT - - __ addptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); -} - - -static void restore_live_registers(GraalStubAssembler* sasm, bool restore_fpu_registers/* = true*/) { - __ block_comment("restore_live_registers"); - - restore_fpu(sasm, restore_fpu_registers); - __ popa(); -} - - -static void restore_live_registers_except_rax(GraalStubAssembler* sasm, bool restore_fpu_registers = true) { - __ block_comment("restore_live_registers_except_rax"); - - restore_fpu(sasm, restore_fpu_registers); - -#ifdef _LP64 - __ movptr(r15, Address(rsp, 0)); - __ movptr(r14, Address(rsp, wordSize)); - __ movptr(r13, Address(rsp, 2 * wordSize)); - __ movptr(r12, Address(rsp, 3 * wordSize)); - __ movptr(r11, Address(rsp, 4 * wordSize)); - __ movptr(r10, Address(rsp, 5 * wordSize)); - __ movptr(r9, Address(rsp, 6 * wordSize)); - __ movptr(r8, Address(rsp, 7 * wordSize)); - __ movptr(rdi, Address(rsp, 8 * wordSize)); - __ movptr(rsi, Address(rsp, 9 * wordSize)); - __ movptr(rbp, Address(rsp, 10 * wordSize)); - // skip rsp - __ movptr(rbx, Address(rsp, 12 * wordSize)); - __ movptr(rdx, Address(rsp, 13 * wordSize)); - __ movptr(rcx, Address(rsp, 14 * wordSize)); - - __ addptr(rsp, 16 * wordSize); -#else - - __ pop(rdi); - __ pop(rsi); - __ pop(rbp); - __ pop(rbx); // skip this value - __ pop(rbx); - __ pop(rdx); - __ pop(rcx); - __ addptr(rsp, BytesPerWord); -#endif // _LP64 -} - -OopMapSet* GraalRuntime::generate_handle_exception(StubID id, GraalStubAssembler *sasm) { - __ block_comment("generate_handle_exception"); - - // incoming parameters - const Register exception_oop = rax; - const Register exception_pc = rdx; - // other registers used in this stub - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); - - // Save registers, if required. - OopMapSet* oop_maps = new OopMapSet(); - OopMap* oop_map = NULL; - switch (id) { - case handle_exception_nofpu_id: - // At this point all registers MAY be live. - oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id); - break; - default: ShouldNotReachHere(); - } - -#ifdef TIERED - // C2 can leave the fpu stack dirty - if (UseSSE < 2) { - __ empty_FPU_stack(); - } -#endif // TIERED - - // verify that only rax, and rdx is valid at this time -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rsi, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - - // verify that rax, contains a valid exception - __ verify_not_null_oop(exception_oop); - - // load address of JavaThread object for thread-local data - NOT_LP64(__ get_thread(thread);) - -#ifdef ASSERT - // check that fields in JavaThread for exception oop and issuing pc are - // empty before writing to them - Label oop_empty; - __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t) NULL_WORD); - __ jcc(Assembler::equal, oop_empty); - __ stop("exception oop already set"); - __ bind(oop_empty); - - Label pc_empty; - __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); - __ jcc(Assembler::equal, pc_empty); - __ stop("exception pc already set"); - __ bind(pc_empty); -#endif - - // save exception oop and issuing pc into JavaThread - // (exception handler will load it from here) - __ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop); - __ movptr(Address(thread, JavaThread::exception_pc_offset()), exception_pc); - - // patch throwing pc into return address (has bci & oop map) - __ movptr(Address(rbp, 1*BytesPerWord), exception_pc); - - // compute the exception handler. - // the exception oop and the throwing pc are read from the fields in JavaThread - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); - oop_maps->add_gc_map(call_offset, oop_map); - - // rax: handler address - // will be the deopt blob if nmethod was deoptimized while we looked up - // handler regardless of whether handler existed in the nmethod. - - // only rax, is valid at this time, all other registers have been destroyed by the runtime call -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rdx, 0xDEAD); - __ movptr(rsi, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - - // patch the return address, this stub will directly return to the exception handler - __ movptr(Address(rbp, 1*BytesPerWord), rax); - - switch (id) { - case handle_exception_nofpu_id: - // Restore the registers that were saved at the beginning. - restore_live_registers(sasm, id == handle_exception_nofpu_id); - break; - default: ShouldNotReachHere(); - } - - return oop_maps; -} - -void GraalRuntime::generate_unwind_exception(GraalStubAssembler *sasm) { - // incoming parameters - const Register exception_oop = rax; - // callee-saved copy of exception_oop during runtime call - const Register exception_oop_callee_saved = NOT_LP64(rsi) LP64_ONLY(r14); - // other registers used in this stub - const Register exception_pc = rdx; - const Register handler_addr = rbx; - const Register thread = NOT_LP64(rdi) LP64_ONLY(r15_thread); - - // verify that only rax is valid at this time -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rdx, 0xDEAD); - __ movptr(rsi, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - -#ifdef ASSERT - // check that fields in JavaThread for exception oop and issuing pc are empty - NOT_LP64(__ get_thread(thread);) - Label oop_empty; - __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), 0); - __ jcc(Assembler::equal, oop_empty); - __ stop("exception oop must be empty"); - __ bind(oop_empty); - - Label pc_empty; - __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); - __ jcc(Assembler::equal, pc_empty); - __ stop("exception pc must be empty"); - __ bind(pc_empty); -#endif - - // clear the FPU stack in case any FPU results are left behind - __ empty_FPU_stack(); - - // save exception_oop in callee-saved register to preserve it during runtime calls - __ verify_not_null_oop(exception_oop); - __ movptr(exception_oop_callee_saved, exception_oop); - - NOT_LP64(__ get_thread(thread);) - // Get return address (is on top of stack after leave). - __ movptr(exception_pc, Address(rsp, 0)); - - // search the exception handler address of the caller (using the return address) - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); - // rax: exception handler address of the caller - - // Only RAX and RSI are valid at this time, all other registers have been destroyed by the call. -#ifdef ASSERT - __ movptr(rbx, 0xDEAD); - __ movptr(rcx, 0xDEAD); - __ movptr(rdx, 0xDEAD); - __ movptr(rdi, 0xDEAD); -#endif - - // move result of call into correct register - __ movptr(handler_addr, rax); - - // Restore exception oop to RAX (required convention of exception handler). - __ movptr(exception_oop, exception_oop_callee_saved); - - // verify that there is really a valid exception in rax - __ verify_not_null_oop(exception_oop); - - // get throwing pc (= return address). - // rdx has been destroyed by the call, so it must be set again - // the pop is also necessary to simulate the effect of a ret(0) - __ pop(exception_pc); - - // Restore SP from BP if the exception PC is a method handle call site. - NOT_LP64(__ get_thread(thread);) - __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); - __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save); - - // continue at exception handler (return address removed) - // note: do *not* remove arguments when unwinding the - // activation since the caller assumes having - // all arguments on the stack when entering the - // runtime to determine the exception handler - // (GC happens at call site with arguments!) - // rax: exception oop - // rdx: throwing pc - // rbx: exception handler - __ jmp(handler_addr); -} - -OopMapSet* GraalRuntime::generate_code_for(StubID id, GraalStubAssembler* sasm) { - - // for better readability - const bool must_gc_arguments = true; - const bool dont_gc_arguments = false; - - // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu - bool save_fpu_registers = true; - - // stub code & info for the different stubs - OopMapSet* oop_maps = NULL; - switch (id) { - - case new_instance_id: - { - Register klass = rdx; // Incoming - Register obj = rax; // Result - __ set_info("new_instance", dont_gc_arguments); - __ enter(); - OopMap* map = save_live_registers(sasm, 2); - int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - __ verify_oop(obj); - __ leave(); - __ ret(0); - - // rax,: new instance - } - - break; - - case new_array_id: - { - Register length = rbx; // Incoming - Register klass = rdx; // Incoming - Register obj = rax; // Result - - __ set_info("new_array", dont_gc_arguments); - - __ enter(); - OopMap* map = save_live_registers(sasm, 3); - int call_offset; - call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_array), klass, length); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - - __ verify_oop(obj); - __ leave(); - __ ret(0); - - // rax,: new array - } - break; - - case new_multi_array_id: - { GraalStubFrame f(sasm, "new_multi_array", dont_gc_arguments); - // rax,: klass - // rbx,: rank - // rcx: address of 1st dimension - OopMap* map = save_live_registers(sasm, 4); - int call_offset = __ call_RT(rax, noreg, CAST_FROM_FN_PTR(address, new_multi_array), rax, rbx, rcx); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - - // rax,: new multi array - __ verify_oop(rax); - } - break; - - case register_finalizer_id: - { - __ set_info("register_finalizer", dont_gc_arguments); - - // This is called via call_runtime so the arguments - // will be place in C abi locations - __ verify_oop(j_rarg0); - __ enter(); - OopMap* oop_map = save_live_registers(sasm, 2 /*num_rt_args */); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), j_rarg0); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - - // Now restore all the live registers - restore_live_registers(sasm); - - __ leave(); - __ ret(0); - } - break; - - case handle_exception_nofpu_id: - { GraalStubFrame f(sasm, "handle_exception", dont_gc_arguments); - oop_maps = generate_handle_exception(id, sasm); - } - break; - - case unwind_exception_call_id: { - // remove the frame from the stack - __ movptr(rsp, rbp); - __ pop(rbp); - - __ set_info("unwind_exception", dont_gc_arguments); - // note: no stubframe since we are about to leave the current - // activation and we are calling a leaf VM function only. - generate_unwind_exception(sasm); - __ should_not_reach_here(); - break; - } - - case OSR_migration_end_id: { - __ enter(); - save_live_registers(sasm, 0); - __ movptr(c_rarg0, j_rarg0); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_end))); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case create_null_pointer_exception_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(rax, noreg, (address)create_null_exception, 0); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers_except_rax(sasm); - __ leave(); - __ ret(0); - break; - } - - case create_out_of_bounds_exception_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 1); - int call_offset = __ call_RT(rax, noreg, (address)create_out_of_bounds_exception, j_rarg0); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers_except_rax(sasm); - __ leave(); - __ ret(0); - break; - } - - case vm_error_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 3); - int call_offset = __ call_RT(noreg, noreg, (address)vm_error, j_rarg0, j_rarg1, j_rarg2); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case log_printf_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 4); - int call_offset = __ call_RT(noreg, noreg, (address)log_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case stub_printf_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 4); - int call_offset = __ call_RT(noreg, noreg, (address)stub_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case log_primitive_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 3); - int call_offset = __ call_RT(noreg, noreg, (address)log_primitive, j_rarg0, j_rarg1, j_rarg2); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case log_object_id: { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 2); - int call_offset = __ call_RT(noreg, noreg, (address)log_object, j_rarg0, j_rarg1); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - __ leave(); - __ ret(0); - break; - } - - case verify_oop_id: { - // We use enter & leave so that a better stack trace is produced in the hs_err file - __ enter(); - __ verify_oop(r13, "Graal verify oop"); - __ leave(); - __ ret(0); - break; - } - - case arithmetic_frem_id: { - __ subptr(rsp, 8); - __ movflt(Address(rsp, 0), xmm1); - __ fld_s(Address(rsp, 0)); - __ movflt(Address(rsp, 0), xmm0); - __ fld_s(Address(rsp, 0)); - Label L; - __ bind(L); - __ fprem(); - __ fwait(); - __ fnstsw_ax(); - __ testl(rax, 0x400); - __ jcc(Assembler::notZero, L); - __ fxch(1); - __ fpop(); - __ fstp_s(Address(rsp, 0)); - __ movflt(xmm0, Address(rsp, 0)); - __ addptr(rsp, 8); - __ ret(0); - break; - } - case arithmetic_drem_id: { - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), xmm1); - __ fld_d(Address(rsp, 0)); - __ movdbl(Address(rsp, 0), xmm0); - __ fld_d(Address(rsp, 0)); - Label L; - __ bind(L); - __ fprem(); - __ fwait(); - __ fnstsw_ax(); - __ testl(rax, 0x400); - __ jcc(Assembler::notZero, L); - __ fxch(1); - __ fpop(); - __ fstp_d(Address(rsp, 0)); - __ movdbl(xmm0, Address(rsp, 0)); - __ addptr(rsp, 8); - __ ret(0); - break; - } - case monitorenter_id: { - Register obj = j_rarg0; - Register lock = j_rarg1; - { - GraalStubFrame f(sasm, "monitorenter", dont_gc_arguments); - OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); - - // Called with store_parameter and not C abi - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), obj, lock); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers(sasm, save_fpu_registers); - } - __ ret(0); - break; - } - case monitorexit_id: { - Register obj = j_rarg0; - Register lock = j_rarg1; - { - GraalStubFrame f(sasm, "monitorexit", dont_gc_arguments); - OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); - - // note: really a leaf routine but must setup last java sp - // => use call_RT for now (speed can be improved by - // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), obj, lock); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers(sasm, save_fpu_registers); - } - __ ret(0); - break; - } - case wb_pre_call_id: { - Register obj = j_rarg0; - { - GraalStubFrame f(sasm, "graal_wb_pre_call", dont_gc_arguments); - OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); - - // note: really a leaf routine but must setup last java sp - // => use call_RT for now (speed can be improved by - // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_pre_call), obj); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers(sasm); - } - __ ret(0); - break; - } - case wb_post_call_id: { - Register obj = j_rarg0; - Register caddr = j_rarg1; - { - GraalStubFrame f(sasm, "graal_wb_post_call", dont_gc_arguments); - OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); - - // note: really a leaf routine but must setup last java sp - // => use call_RT for now (speed can be improved by - // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_post_call), obj, caddr); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers(sasm); - } - __ ret(0); - break; - } - - - case identity_hash_code_id: { - Register obj = j_rarg0; // Incoming - __ set_info("identity_hash_code", dont_gc_arguments); - __ enter(); - OopMap* map = save_live_registers(sasm, 1); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, identity_hash_code), obj); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - __ leave(); - __ ret(0); - break; - } - case thread_is_interrupted_id: { - Register thread = j_rarg0; - Register clear_interrupted = j_rarg1; - - __ set_info("identity_hash_code", dont_gc_arguments); - __ enter(); - OopMap* map = save_live_registers(sasm, 1); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, thread_is_interrupted), thread, clear_interrupted); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_rax(sasm); - __ leave(); - __ ret(0); - break; - } - - default: - { GraalStubFrame f(sasm, "unimplemented entry", dont_gc_arguments); - __ movptr(rax, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax); - __ should_not_reach_here(); - } - break; - } - return oop_maps; -} - -#undef __ diff -r 57113d21ce36 -r f9a65a0e626b src/cpu/x86/vm/graalStubAssembler_x86.cpp --- a/src/cpu/x86/vm/graalStubAssembler_x86.cpp Mon May 13 16:46:39 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 1999, 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. - * - */ - -#include "precompiled.hpp" -#include "graal/graalRuntime.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc_interface/collectedHeap.hpp" -#include "interpreter/interpreter.hpp" -#include "oops/arrayOop.hpp" -#include "oops/markOop.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/os.hpp" -#include "runtime/stubRoutines.hpp" - -#ifndef PRODUCT - -void GraalStubAssembler::verify_stack_oop(int stack_offset) { - if (!VerifyOops) return; - verify_oop_addr(Address(rsp, stack_offset)); -} - -void GraalStubAssembler::verify_not_null_oop(Register r) { - if (!VerifyOops) return; - Label not_null; - testptr(r, r); - jcc(Assembler::notZero, not_null); - stop("non-null oop required"); - bind(not_null); - verify_oop(r); -} - -#endif // ifndef PRODUCT diff -r 57113d21ce36 -r f9a65a0e626b src/gpu/ptx/gpu_ptx.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/ptx/gpu_ptx.cpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,168 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/gpu.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" + +void * gpu::Ptx::_device_context; + +gpu::Ptx::cuda_cu_init_func_t gpu::Ptx::_cuda_cu_init; +gpu::Ptx::cuda_cu_ctx_create_func_t gpu::Ptx::_cuda_cu_ctx_create; +gpu::Ptx::cuda_cu_ctx_detach_func_t gpu::Ptx::_cuda_cu_ctx_detach; +gpu::Ptx::cuda_cu_ctx_synchronize_func_t gpu::Ptx::_cuda_cu_ctx_synchronize; +gpu::Ptx::cuda_cu_device_get_count_func_t gpu::Ptx::_cuda_cu_device_get_count; +gpu::Ptx::cuda_cu_device_get_name_func_t gpu::Ptx::_cuda_cu_device_get_name; +gpu::Ptx::cuda_cu_device_get_func_t gpu::Ptx::_cuda_cu_device_get; +gpu::Ptx::cuda_cu_device_compute_capability_func_t gpu::Ptx::_cuda_cu_device_compute_capability; +gpu::Ptx::cuda_cu_launch_kernel_func_t gpu::Ptx::_cuda_cu_launch_kernel; +gpu::Ptx::cuda_cu_module_get_function_func_t gpu::Ptx::_cuda_cu_module_get_function; +gpu::Ptx::cuda_cu_module_load_data_ex_func_t gpu::Ptx::_cuda_cu_module_load_data_ex; + +void gpu::probe_linkage() { +#ifdef __APPLE__ + set_gpu_linkage(gpu::Ptx::probe_linkage_apple()); +#else + set_gpu_linkage(false); +#endif +} + +void gpu::initialize_gpu() { + if (gpu::has_gpu_linkage()) { + set_initialized(gpu::Ptx::initialize_gpu()); + } +} + +void gpu::generate_kernel(unsigned char *code, int code_len, const char *name) { + if (gpu::has_gpu_linkage()) { + gpu::Ptx::generate_kernel(code, code_len, name); + } +} + +#define __CUDA_API_VERSION 5000 + +bool gpu::Ptx::initialize_gpu() { + int status = _cuda_cu_init(0, __CUDA_API_VERSION); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_init: %d", status); + } + + int device_count = 0; + status = _cuda_cu_device_get_count(&device_count); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_device_get_count(%d): %d", device_count, status); + } + + int device_id = 0, cu_device = 0; + status = _cuda_cu_device_get(&cu_device, device_id); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_device_get(%d): %d", cu_device, status); + } + + int major, minor; + status = _cuda_cu_device_compute_capability(&major, &minor, cu_device); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_device_compute_capability(major %d, minor %d): %d", + major, minor, status); + } + + char device_name[256]; + status = _cuda_cu_device_get_name(device_name, 256, cu_device); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_device_get_name(%s): %d", device_name, status); + } + + status = _cuda_cu_ctx_create(&_device_context, 0, cu_device); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_ctx_create(%x): %d", _device_context, status); + } + + return status == 0; // CUDA_SUCCESS +} + +void gpu::Ptx::generate_kernel(unsigned char *code, int code_len, const char *name) { + + void *cu_module; + const unsigned int jit_num_options = 3; + int *jit_options = new int[jit_num_options]; + void **jit_option_values = new void *[jit_num_options]; + + jit_options[0] = 4; // CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES + int jit_log_buffer_size = 1024; + jit_option_values[0] = (void *)(size_t)jit_log_buffer_size; + + jit_options[1] = 3; // CU_JIT_INFO_LOG_BUFFER + char *jit_log_buffer = new char[jit_log_buffer_size]; + jit_option_values[1] = jit_log_buffer; + + jit_options[2] = 0; // CU_JIT_MAX_REGISTERS + int jit_register_count = 32; + jit_option_values[2] = (void *)(size_t)jit_register_count; + + int status = _cuda_cu_module_load_data_ex(&cu_module, code, + jit_num_options, jit_options, (void **)jit_option_values); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_module_load_data_ex(%x): %d", cu_module, status); + tty->print_cr("gpu_ptx::jit_log_buffer\n%s", jit_log_buffer); + } + + void *cu_function; + + status = _cuda_cu_module_get_function(&cu_function, cu_module, name); + if (TraceWarpLoading) { + tty->print_cr("gpu_ptx::_cuda_cu_module_get_function(%s):%x %d", name, cu_function, status); + } +} + + +#ifdef __APPLE__ +bool gpu::Ptx::probe_linkage_apple() { + void *handle = dlopen("/usr/local/cuda/lib/libcuda.dylib", RTLD_LAZY); + if (handle != NULL) { + _cuda_cu_init = + CAST_TO_FN_PTR(cuda_cu_init_func_t, dlsym(handle, "cuInit")); + _cuda_cu_ctx_create = + CAST_TO_FN_PTR(cuda_cu_ctx_create_func_t, dlsym(handle, "cuCtxCreate")); + _cuda_cu_ctx_detach = + CAST_TO_FN_PTR(cuda_cu_ctx_detach_func_t, dlsym(handle, "cuCtxDetach")); + _cuda_cu_ctx_synchronize = + CAST_TO_FN_PTR(cuda_cu_ctx_synchronize_func_t, dlsym(handle, "cuCtxSynchronize")); + _cuda_cu_device_get_count = + CAST_TO_FN_PTR(cuda_cu_device_get_count_func_t, dlsym(handle, "cuDeviceGetCount")); + _cuda_cu_device_get_name = + CAST_TO_FN_PTR(cuda_cu_device_get_name_func_t, dlsym(handle, "cuDeviceGetName")); + _cuda_cu_device_get = + CAST_TO_FN_PTR(cuda_cu_device_get_func_t, dlsym(handle, "cuDeviceGet")); + _cuda_cu_device_compute_capability = + CAST_TO_FN_PTR(cuda_cu_device_compute_capability_func_t, dlsym(handle, "cuDeviceComputeCapability")); + _cuda_cu_module_get_function = + CAST_TO_FN_PTR(cuda_cu_module_get_function_func_t, dlsym(handle, "cuModuleGetFunction")); + _cuda_cu_module_load_data_ex = + CAST_TO_FN_PTR(cuda_cu_module_load_data_ex_func_t, dlsym(handle, "cuModuleLoadDataEx")); + return true; + } + return false; +} +#endif \ No newline at end of file diff -r 57113d21ce36 -r f9a65a0e626b src/gpu/ptx/gpu_ptx.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gpu/ptx/gpu_ptx.hpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,68 @@ +/* + * 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. + * + */ + +#ifndef GPU_PTX_HPP +#define GPU_PTX_HPP + +class Ptx { + friend class gpu; + + protected: + static void probe_linkage(); +#ifdef __APPLE__ + static bool probe_linkage_apple(); +#endif + static bool initialize_gpu(); + static void generate_kernel(unsigned char *code, int code_len, const char *name); + +private: + typedef int (*cuda_cu_init_func_t)(unsigned int, int); + typedef int (*cuda_cu_ctx_create_func_t)(void *, int, int); + typedef int (*cuda_cu_ctx_detach_func_t)(int *); + typedef int (*cuda_cu_ctx_synchronize_func_t)(int *); + typedef int (*cuda_cu_device_get_count_func_t)(int *); + typedef int (*cuda_cu_device_get_name_func_t)(char *, int, int); + typedef int (*cuda_cu_device_get_func_t)(int *, int); + typedef int (*cuda_cu_device_compute_capability_func_t)(int *, int *, int); + typedef int (*cuda_cu_launch_kernel_func_t)(int *, int *, int); + typedef int (*cuda_cu_module_get_function_func_t)(void *, void *, const char *); + typedef int (*cuda_cu_module_load_data_ex_func_t)(void *, void *, unsigned int, int *, void **); + + static cuda_cu_init_func_t _cuda_cu_init; + static cuda_cu_ctx_create_func_t _cuda_cu_ctx_create; + static cuda_cu_ctx_detach_func_t _cuda_cu_ctx_detach; + static cuda_cu_ctx_synchronize_func_t _cuda_cu_ctx_synchronize; + static cuda_cu_device_get_count_func_t _cuda_cu_device_get_count; + static cuda_cu_device_get_name_func_t _cuda_cu_device_get_name; + static cuda_cu_device_get_func_t _cuda_cu_device_get; + static cuda_cu_device_compute_capability_func_t _cuda_cu_device_compute_capability; + static cuda_cu_launch_kernel_func_t _cuda_cu_launch_kernel; + static cuda_cu_module_get_function_func_t _cuda_cu_module_get_function; + static cuda_cu_module_load_data_ex_func_t _cuda_cu_module_load_data_ex; + +protected: + static void * _device_context; +}; + +#endif // GPU_PTX_HPP diff -r 57113d21ce36 -r f9a65a0e626b src/os/bsd/vm/gpu_bsd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/bsd/vm/gpu_bsd.cpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "runtime/gpu.hpp" +#include "utilities/ostream.hpp" + +#ifdef __APPLE__ +#include +#include +#endif + +void gpu::probe_gpu() { +#ifdef __APPLE__ + set_available(gpu::Bsd::probe_gpu_apple()); + if (TraceWarpLoading) { + tty->print_cr("gpu_bsd::probe_gpu(APPLE): %d", gpu::is_available()); + } +#else + if (TraceWarpLoading) { + tty->print_cr("gpu_bsd::probe_gpu(not APPLE)"); + } + set_available(false); +#endif +} + +#ifdef __APPLE__ +/* + * This is rudimentary at best, but until we decide on a CUDA Compiler Compatibility + * level, this will have to suffice. + */ +bool gpu::Bsd::probe_gpu_apple() { + CGError err = CGDisplayNoErr; + CGDisplayCount displayCount = 0; + CFDataRef vendorID, deviceID, model; + CGDirectDisplayID *displays; + IOOptionBits options = kIORegistryIterateRecursively | kIORegistryIterateParents; + io_registry_entry_t displayPort; + + err = CGGetActiveDisplayList(0, NULL, &displayCount); + displays = (CGDirectDisplayID *)calloc((size_t)displayCount, sizeof(CGDirectDisplayID)); + err = CGGetActiveDisplayList(displayCount, displays, &displayCount); + + for (CGDisplayCount i = 0; i < displayCount; i++) { + displayPort = CGDisplayIOServicePort(displays[i]); + vendorID = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("vendor-id"), + kCFAllocatorDefault, options); + deviceID = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("device-id"), + kCFAllocatorDefault, options); + model = (CFDataRef)IORegistryEntrySearchCFProperty(displayPort, kIOServicePlane, CFSTR("model"), + kCFAllocatorDefault, options); + if (TraceWarpLoading) { + tty->print_cr("vendor: 0x%08X", *((UInt32*)CFDataGetBytePtr(vendorID))); + tty->print_cr("device: 0x%08X", *((UInt32*)CFDataGetBytePtr(deviceID))); + tty->print_cr("model: %s", CFDataGetBytePtr(model)); + } + UInt32 vendor = *((UInt32*)CFDataGetBytePtr(vendorID)); + if (vendor != 0x10DE) { + return false; + } else { + /* + * see https://developer.nvidia.com/cuda-gpus + * see http://en.wikipedia.org/wiki/CUDA#Supported_GPUs + * see http://www.pcidatabase.com/reports.php?type=csv + * + * Only supporting GK104, GK106, GK107 and GK110 GPUs for now, + * which is CUDA Computer Capability 3.0 and greater. + */ + switch (*((UInt32*)CFDataGetBytePtr(deviceID))) { + case 0x11C0: + return true; // NVIDIA GeForce GTX 660 + default: + return false; + } + } + } + return false; +} +#endif diff -r 57113d21ce36 -r f9a65a0e626b src/os/bsd/vm/gpu_bsd.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/os/bsd/vm/gpu_bsd.hpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_BSD_VM_GPU_BSD_HPP +#define OS_BSD_VM_GPU_BSD_HPP + + +class Bsd { + friend class gpu; + + protected: + static bool probe_gpu(); +#ifdef __APPLE__ + static bool probe_gpu_apple(); +#endif +}; + +#endif // OS_BSD_VM_GPU_BSD_HPP diff -r 57113d21ce36 -r f9a65a0e626b src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java --- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Mon May 13 16:46:39 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Mon May 13 17:11:31 2013 +0200 @@ -98,7 +98,12 @@ private static String getJsHelperText() { InputStream is = null; - StringBuilder sb = new StringBuilder("importPackage(Packages.com.sun.hotspot.igv.filter);importPackage(Packages.com.sun.hotspot.igv.graph);importPackage(Packages.com.sun.hotspot.igv.data);importPackage(Packages.com.sun.hotspot.igv.util);importPackage(java.awt);"); + StringBuilder sb = new StringBuilder("if (typeof importPackage === 'undefined') { try { load('nashorn:mozilla_compat.js'); } catch (e) {} }" + + "importPackage(Packages.com.sun.hotspot.igv.filter);" + + "importPackage(Packages.com.sun.hotspot.igv.graph);" + + "importPackage(Packages.com.sun.hotspot.igv.data);" + + "importPackage(Packages.com.sun.hotspot.igv.util);" + + "importPackage(java.awt);"); try { FileObject fo = FileUtil.getConfigRoot().getFileObject(JAVASCRIPT_HELPER_ID); is = fo.getInputStream(); diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Mon May 13 17:11:31 2013 +0200 @@ -183,7 +183,7 @@ do_klass(Long_klass, java_lang_Long, Pre ) \ \ /* Support for Graal */ \ - do_klass(GraalBitMap_klass, java_util_BitSet, Opt) \ + do_klass(BitSet_klass, java_util_BitSet, Opt) \ /* graal.hotspot */ \ do_klass(HotSpotCompilationResult_klass, com_oracle_graal_hotspot_HotSpotCompilationResult, Opt) \ do_klass(HotSpotRuntimeCallTarget_klass, com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, Opt) \ @@ -205,6 +205,7 @@ do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue, Opt) \ do_klass(BytecodePosition_klass, com_oracle_graal_api_code_BytecodePosition, Opt) \ do_klass(DebugInfo_klass, com_oracle_graal_api_code_DebugInfo, Opt) \ + do_klass(RegisterSaveLayout_klass, com_oracle_graal_api_code_RegisterSaveLayout, Opt) \ do_klass(BytecodeFrame_klass, com_oracle_graal_api_code_BytecodeFrame, Opt) \ do_klass(CompilationResult_klass, com_oracle_graal_api_code_CompilationResult, Opt) \ do_klass(CompilationResult_Call_klass, com_oracle_graal_api_code_CompilationResult_Call, Opt) \ diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon May 13 17:11:31 2013 +0200 @@ -341,6 +341,7 @@ template(com_oracle_graal_api_code_RegisterValue, "com/oracle/graal/api/code/RegisterValue") \ template(com_oracle_graal_api_code_StackSlot, "com/oracle/graal/api/code/StackSlot") \ template(com_oracle_graal_api_code_VirtualObject, "com/oracle/graal/api/code/VirtualObject") \ + template(com_oracle_graal_api_code_RegisterSaveLayout, "com/oracle/graal/api/code/RegisterSaveLayout") \ template(com_oracle_graal_api_code_InvalidInstalledCodeException, "com/oracle/graal/api/code/InvalidInstalledCodeException") \ template(startCompiler_name, "startCompiler") \ template(bootstrap_name, "bootstrap") \ diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Mon May 13 17:11:31 2013 +0200 @@ -68,16 +68,16 @@ const int MapWordBits = 64; -static bool is_bit_set(oop bit_map, int i) { - jint extra_idx = i / MapWordBits; - arrayOop extra = (arrayOop) GraalBitMap::words(bit_map); - assert(extra_idx >= 0 && extra_idx < extra->length(), "unexpected index"); - jlong word = ((jlong*) extra->base(T_LONG))[extra_idx]; +static bool is_bit_set(oop bitset, int i) { + jint words_idx = i / MapWordBits; + arrayOop words = (arrayOop) BitSet::words(bitset); + assert(words_idx >= 0 && words_idx < words->length(), "unexpected index"); + jlong word = ((jlong*) words->base(T_LONG))[words_idx]; return (word & (1LL << (i % MapWordBits))) != 0; } -static int bitmap_size(oop bit_map) { - arrayOop arr = (arrayOop) GraalBitMap::words(bit_map); +static int bitset_size(oop bitset) { + arrayOop arr = (arrayOop) BitSet::words(bitset); return arr->length() * MapWordBits; } @@ -86,23 +86,24 @@ OopMap* map = new OopMap(total_frame_size, parameter_count); oop register_map = (oop) DebugInfo::registerRefMap(debug_info); oop frame_map = (oop) DebugInfo::frameRefMap(debug_info); + oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); if (register_map != NULL) { for (jint i = 0; i < RegisterImpl::number_of_registers; i++) { bool is_oop = is_bit_set(register_map, i); - VMReg reg = get_hotspot_reg(i); + VMReg hotspot_reg = get_hotspot_reg(i); if (is_oop) { - map->set_oop(reg); + map->set_oop(hotspot_reg); } else { - map->set_value(reg); + map->set_value(hotspot_reg); } } } - for (jint i = 0; i < bitmap_size(frame_map); i++) { + for (jint i = 0; i < bitset_size(frame_map); i++) { bool is_oop = is_bit_set(frame_map, i); // HotSpot stack slots are 4 bytes - VMReg reg = VMRegImpl::stack2reg(i * 2); + VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word); if (is_oop) { map->set_oop(reg); } else { @@ -110,6 +111,26 @@ } } + if (callee_save_info != NULL) { + objArrayOop registers = (objArrayOop) RegisterSaveLayout::registers(callee_save_info); + arrayOop slots = (arrayOop) RegisterSaveLayout::slots(callee_save_info); + for (jint i = 0; i < slots->length(); i++) { + oop graal_reg = registers->obj_at(i); + jint graal_reg_number = code_Register::number(graal_reg); + VMReg hotspot_reg = get_hotspot_reg(graal_reg_number); + // HotSpot stack slots are 4 bytes + jint graal_slot = ((jint*) slots->base(T_INT))[i]; + jint hotspot_slot = graal_slot * VMRegImpl::slots_per_word; + VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); + map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); +#ifdef _LP64 + // (copied from generate_oop_map() in c1_Runtime1_x86.cpp) + VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1); + map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next()); +#endif + } + } + return map; } @@ -330,7 +351,7 @@ } // constructor used to create a method -CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations) { +CodeInstaller::CodeInstaller(Handle& comp_result, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations) { GraalCompiler::initialize_buffer_blob(); CodeBuffer buffer(JavaThread::current()->get_buffer_blob()); jobject comp_result_obj = JNIHandles::make_local(comp_result()); @@ -339,7 +360,7 @@ { No_Safepoint_Verifier no_safepoint; - initialize_fields(JNIHandles::resolve(comp_result_obj), method); + initialize_fields(JNIHandles::resolve(comp_result_obj)); initialize_buffer(buffer); process_exception_handlers(); } @@ -347,17 +368,36 @@ int stack_slots = _total_frame_size / HeapWordSize; // conversion to words GrowableArray* leaf_graph_ids = get_leaf_graph_ids(comp_result); - result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, - GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations); + if (_stubName != NULL) { + char* name = strdup(java_lang_String::as_utf8_string(_stubName)); + cb = RuntimeStub::new_runtime_stub(name, + &buffer, + CodeOffsets::frame_never_safe, + stack_slots, + _debug_recorder->_oopmaps, + false); + result = GraalEnv::ok; + } else { + nmethod* nm = NULL; + methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(comp_result)); + result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, false, leaf_graph_ids, installed_code, triggered_deoptimizations); + cb = nm; + } } -void CodeInstaller::initialize_fields(oop comp_result, methodHandle method) { +void CodeInstaller::initialize_fields(oop comp_result) { _comp_result = HotSpotCompilationResult::comp(comp_result); - if (!method.is_null()) { + oop hotspotJavaMethod = HotSpotCompilationResult::method(comp_result); + if (hotspotJavaMethod != NULL) { + methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod); _parameter_count = method->size_of_parameters(); TRACE_graal_1("installing code for %s", method->name_and_sig_as_C_string()); + } else { + // TODO (ds) not sure if this is correct - only used in OopMap constructor for non-product builds + _parameter_count = 0; } - _name = HotSpotCompilationResult::name(comp_result); + _stubName = HotSpotCompilationResult::stubName(comp_result); _sites = (arrayOop) HotSpotCompilationResult::sites(comp_result); _exception_handlers = (arrayOop) HotSpotCompilationResult::exceptionHandlers(comp_result); @@ -640,8 +680,14 @@ if (target->is_a(SystemDictionary::HotSpotInstalledCode_klass())) { assert(inst->is_jump(), "jump expected"); - nmethod* nm = (nmethod*) HotSpotInstalledCode::nmethod(target); - nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + CodeBlob* cb = (CodeBlob*) (address) HotSpotInstalledCode::codeBlob(target); + assert(cb != NULL, "npe"); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + } else { + nativeJump_at((address)inst)->set_jump_destination(cb->code_begin()); + } _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); return; diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Mon May 13 17:11:31 2013 +0200 @@ -51,7 +51,7 @@ Arena _arena; oop _comp_result; - oop _name; + oop _stubName; arrayOop _sites; arrayOop _exception_handlers; CodeOffsets _offsets; @@ -76,17 +76,13 @@ public: - // constructor used to create a method - CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations); - - // constructor used to create a stub - CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id); + CodeInstaller(Handle& comp_result, GraalEnv::CodeInstallResult& result, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations); static address runtime_call_target_address(oop runtime_call); private: // extract the fields of the CompilationResult - void initialize_fields(oop target_method, methodHandle method); + void initialize_fields(oop target_method); void initialize_assumptions(oop target_method); // perform data and call relocation on the CodeBuffer diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Mon May 13 17:11:31 2013 +0200 @@ -28,6 +28,7 @@ #include "graal/graalJavaAccess.hpp" #include "graal/graalVMToCompiler.hpp" #include "graal/graalCompilerToVM.hpp" +#include "graal/graalCompilerToGPU.hpp" #include "graal/graalEnv.hpp" #include "graal/graalRuntime.hpp" #include "runtime/arguments.hpp" @@ -56,7 +57,6 @@ _deopted_leaf_graph_count = 0; initialize_buffer_blob(); - GraalRuntime::initialize(THREAD->get_buffer_blob()); JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment(); jclass klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToVMImpl"); @@ -65,6 +65,13 @@ vm_abort(false); } env->RegisterNatives(klass, CompilerToVM_methods, CompilerToVM_methods_count()); + + klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToGPUImpl"); + if (klass == NULL) { + tty->print_cr("graal CompilerToGPUImpl class not found"); + vm_abort(false); + } + env->RegisterNatives(klass, CompilerToGPU_methods, CompilerToGPU_methods_count()); ResourceMark rm; HandleMark hm; diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCompilerToGPU.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalCompilerToGPU.cpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include "precompiled.hpp" + +#include "graal/graalCompiler.hpp" +#include "graal/graalEnv.hpp" +#include "runtime/gpu.hpp" + + +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_graal_3("CompilerToGPU::" #name); \ + GRAAL_VM_ENTRY_MARK; \ + +// Entry to native method implementation that calls a JNI function +// and hence cannot transition current thread to '_thread_in_vm'. +#define C2V_ENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_graal_3("CompilerToGPU::" #name); \ + +#define C2V_END } + + +C2V_VMENTRY(jlong, generateKernel, (JNIEnv *env, jobject, jbyteArray code, jstring name)) + if (gpu::is_available() == false || gpu::has_gpu_linkage() == false && gpu::is_initialized()) { + tty->print_cr("generateKernel - not available / no linkage / not initialized"); + return 0; + } + jboolean is_copy; + jbyte *bytes = env->GetByteArrayElements(code, &is_copy); + jint len = env->GetArrayLength(code); + const char *namestr = env->GetStringUTFChars(name, &is_copy); + gpu::generate_kernel((unsigned char *)bytes, len, namestr); + env->ReleaseByteArrayElements(code, bytes, 0); + env->ReleaseStringUTFChars(name, namestr); + + return 42; +C2V_END + +C2V_VMENTRY(jboolean, deviceInit, (JNIEnv *env, jobject)) + if (gpu::is_available() == false || gpu::has_gpu_linkage() == false) { + tty->print_cr("deviceInit - not available / no linkage"); + return false; + } + if (gpu::is_initialized()) { + tty->print_cr("deviceInit - already initialized"); + return true; + } + gpu::initialize_gpu(); + return gpu::is_initialized(); +C2V_END + +C2V_VMENTRY(jboolean, deviceDetach, (JNIEnv *env, jobject)) +return true; +C2V_END + + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) + +#define RESOLVED_TYPE "Lcom/oracle/graal/api/meta/ResolvedJavaType;" +#define TYPE "Lcom/oracle/graal/api/meta/JavaType;" +#define METHOD "Lcom/oracle/graal/api/meta/JavaMethod;" +#define FIELD "Lcom/oracle/graal/api/meta/JavaField;" +#define SIGNATURE "Lcom/oracle/graal/api/meta/Signature;" +#define CONSTANT_POOL "Lcom/oracle/graal/api/meta/ConstantPool;" +#define CONSTANT "Lcom/oracle/graal/api/meta/Constant;" +#define KIND "Lcom/oracle/graal/api/meta/Kind;" +#define LOCAL "Lcom/oracle/graal/api/meta/Local;" +#define RUNTIME_CALL "Lcom/oracle/graal/api/code/RuntimeCall;" +#define EXCEPTION_HANDLERS "[Lcom/oracle/graal/api/meta/ExceptionHandler;" +#define REFLECT_METHOD "Ljava/lang/reflect/Method;" +#define REFLECT_CONSTRUCTOR "Ljava/lang/reflect/Constructor;" +#define REFLECT_FIELD "Ljava/lang/reflect/Field;" +#define STRING "Ljava/lang/String;" +#define OBJECT "Ljava/lang/Object;" +#define CLASS "Ljava/lang/Class;" +#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" +#define HS_RESOLVED_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;" +#define HS_RESOLVED_JAVA_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaType;" +#define HS_RESOLVED_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;" +#define HS_RESOLVED_FIELD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;" +#define HS_COMP_RESULT "Lcom/oracle/graal/hotspot/HotSpotCompilationResult;" +#define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" +#define HS_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;" +#define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" +#define METHOD_DATA "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;" +#define METASPACE_METHOD "J" +#define METASPACE_METHOD_DATA "J" +#define NMETHOD "J" +#define GPUSPACE_METHOD "J" + +JNINativeMethod CompilerToGPU_methods[] = { + {CC"generateKernel", CC"([B" STRING ")"GPUSPACE_METHOD, FN_PTR(generateKernel)}, + {CC"deviceInit", CC"()Z", FN_PTR(deviceInit)}, + {CC"deviceDetach", CC"()Z", FN_PTR(deviceDetach)}, +}; + +int CompilerToGPU_methods_count() { + return sizeof(CompilerToGPU_methods) / sizeof(JNINativeMethod); +} + diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCompilerToGPU.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/graal/graalCompilerToGPU.hpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#ifndef SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP +#define SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP + +#include "prims/jni.h" + +extern JNINativeMethod CompilerToGPU_methods[]; +int CompilerToGPU_methods_count(); + + +#endif // SHARE_VM_GRAAL_GRAAL_COMPILER_TO_GPU_HPP diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon May 13 17:11:31 2013 +0200 @@ -276,6 +276,10 @@ HotSpotResolvedJavaMethod::set_name(hotspot_method, name()); HotSpotResolvedJavaMethod::set_codeSize(hotspot_method, method->code_size()); HotSpotResolvedJavaMethod::set_exceptionHandlerCount(hotspot_method, method->exception_table_length()); + HotSpotResolvedJavaMethod::set_callerSensitive(hotspot_method, method->caller_sensitive()); + HotSpotResolvedJavaMethod::set_forceInline(hotspot_method, method->force_inline()); + HotSpotResolvedJavaMethod::set_dontInline(hotspot_method, method->dont_inline()); + HotSpotResolvedJavaMethod::set_ignoredBySecurityStackWalk(hotspot_method, method->is_ignored_by_security_stack_walk()); C2V_END C2V_VMENTRY(jboolean, isMethodCompilable,(JNIEnv *, jobject, jlong metaspace_method)) @@ -387,35 +391,52 @@ oop result = NULL; constantTag tag = cp->tag_at(index); - if (tag.is_int()) { - result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_0); - } else if (tag.is_long()) { - result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_0); - } else if (tag.is_float()) { - result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_0); - } else if (tag.is_double()) { - result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_0); - } else if (tag.is_string()) { - oop string = NULL; - if (cp->is_pseudo_string_at(index)) { - int obj_index = cp->cp_to_object_index(index); - string = cp->pseudo_string_at(index, obj_index); - } else { - string = cp->string_at(index, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - // TODO: Gracefully exit compilation. - fatal("out of memory during compilation!"); - return NULL; - } + + switch (tag.value()) { + case JVM_CONSTANT_Integer: + result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_NULL); + break; + + case JVM_CONSTANT_Long: + result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_NULL); + break; + + case JVM_CONSTANT_Float: + result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_NULL); + break; + + case JVM_CONSTANT_Double: + result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_NULL); + break; + + case JVM_CONSTANT_Class: + case JVM_CONSTANT_UnresolvedClass: + case JVM_CONSTANT_UnresolvedClassInError: + { + Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); + result = type(); + break; } - result = VMToCompiler::createConstantObject(string, CHECK_0); - } else if (tag.is_klass() || tag.is_unresolved_klass()) { - Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); - result = type(); - } else { - tty->print("unknown constant pool tag (%s) at cpi %d in %s: ", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string()); - ShouldNotReachHere(); + + case JVM_CONSTANT_String: + { + oop result_oop = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); + result = VMToCompiler::createConstantObject(result_oop, CHECK_NULL); + break; + } + + case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodHandleInError: + case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_MethodTypeInError: + { + oop result_oop = cp->resolve_constant_at(index, CHECK_NULL); + result = VMToCompiler::createConstantObject(result_oop, CHECK_NULL); + break; + } + + default: + fatal(err_msg_res("unknown constant pool tag %s at cpi %d in %s", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string())); } return JNIHandles::make_local(THREAD, result); @@ -585,8 +606,8 @@ return JNIHandles::make_local(field_array()); C2V_END -C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong stub)) - address target_addr = (address) stub; +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr)) + address target_addr = (address) addr; if (target_addr != 0x0) { int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); @@ -612,24 +633,18 @@ return id; } -BasicType basicTypes[] = { T_BOOLEAN, T_BYTE, T_SHORT, T_CHAR, T_INT, T_FLOAT, T_LONG, T_DOUBLE, T_OBJECT }; -int basicTypeCount = sizeof(basicTypes) / sizeof(BasicType); - C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config)) #define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0) #define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0) #define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0) -#define set_stub(name, value) do { set_long(name, (jlong) value); } while (0) +#define set_address(name, value) do { set_long(name, (jlong) value); } while (0) #define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0) #define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0) guarantee(HeapWordSize == sizeof(char*), "Graal assumption that HeadWordSize == machine word size is wrong"); -#ifdef _WIN64 - set_boolean("windowsOs", true); -#else - set_boolean("windowsOs", false); -#endif + + set_boolean("cAssertions", DEBUG_ONLY(true) NOT_DEBUG(false)); set_boolean("verifyOops", VerifyOops); set_boolean("ciTime", CITime); set_boolean("compileTheWorld", CompileTheWorld); @@ -661,6 +676,7 @@ set_int("threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset())); set_int("threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset())); set_int("threadObjectOffset", in_bytes(JavaThread::threadObj_offset())); + set_int("threadIsMethodHandleReturnOffset", in_bytes(JavaThread::is_method_handle_return_offset())); set_int("osThreadOffset", in_bytes(JavaThread::osthread_offset())); set_int("osThreadInterruptedOffset", in_bytes(OSThread::interrupted_offset())); set_int("unlockedMask", (int) markOopDesc::unlocked_value); @@ -699,6 +715,7 @@ set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset())); + set_int("pendingExceptionOffset", in_bytes(ThreadShadow::pending_exception_offset())); set_int("pendingDeoptimizationOffset", in_bytes(ThreadShadow::pending_deoptimization_offset())); set_int("metaspaceArrayLengthOffset", Array::length_offset_in_bytes()); @@ -721,6 +738,10 @@ set_int("threadTlabStartOffset", in_bytes(JavaThread::tlab_start_offset())); set_int("threadTlabSizeOffset", in_bytes(JavaThread::tlab_size_offset())); set_int("threadAllocatedBytesOffset", in_bytes(JavaThread::allocated_bytes_offset())); + set_int("threadLastJavaSpOffset", in_bytes(JavaThread::last_Java_sp_offset())); + set_int("threadLastJavaFpOffset", in_bytes(JavaThread::last_Java_fp_offset())); + set_int("threadLastJavaPcOffset", in_bytes(JavaThread::last_Java_pc_offset())); + set_int("threadObjectResultOffset", in_bytes(JavaThread::vm_result_offset())); set_int("tlabSlowAllocationsOffset", in_bytes(JavaThread::tlab_slow_allocations_offset())); set_int("tlabFastRefillWasteOffset", in_bytes(JavaThread::tlab_fast_refill_waste_offset())); set_int("tlabNumberOfRefillsOffset", in_bytes(JavaThread::tlab_number_of_refills_offset())); @@ -730,6 +751,10 @@ set_boolean("tlabStats", TLABStats); set_boolean("inlineContiguousAllocationSupported", !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc()); + set_long("verifyOopCounterAddress", (jlong)(address) StubRoutines::verify_oop_count_addr()); + set_long("verifyOopMask", Universe::verify_oop_mask()); + set_long("verifyOopBits", Universe::verify_oop_bits()); + set_long("arrayPrototypeMarkWord", (intptr_t)markOopDesc::prototype()); set_int("layoutHelperLog2ElementSizeShift", Klass::_lh_log2_element_size_shift); set_int("layoutHelperLog2ElementSizeMask", Klass::_lh_log2_element_size_mask); @@ -741,43 +766,39 @@ set_int("layoutHelperHeaderSizeMask", Klass::_lh_header_size_mask); set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset())); - - set_stub("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id)); - set_stub("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id)); + set_address("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub()); + set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); + set_address("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis)); + set_address("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos)); + set_address("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); + set_address("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); + set_address("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); + set_address("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock()); + set_address("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock()); + set_address("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt()); + set_address("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt()); - set_stub("newInstanceStub", GraalRuntime::entry_for(GraalRuntime::new_instance_id)); - set_stub("newArrayStub", GraalRuntime::entry_for(GraalRuntime::new_array_id)); - set_stub("newMultiArrayStub", GraalRuntime::entry_for(GraalRuntime::new_multi_array_id)); - set_stub("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id)); - set_stub("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id)); - set_stub("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub()); - set_stub("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id)); - set_stub("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); - set_stub("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id)); - set_stub("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id)); - set_stub("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id)); - set_stub("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id)); - set_stub("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap()); - set_stub("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id)); - set_stub("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id)); - set_stub("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id)); - set_stub("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id)); - set_stub("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id)); - set_stub("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis)); - set_stub("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos)); - set_stub("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id)); - set_stub("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id)); - set_stub("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); - set_stub("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); - set_stub("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); - set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id)); - set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id)); - set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id)); - set_stub("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id)); - set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock()); - set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock()); - set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt()); - set_stub("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt()); + set_address("newInstanceAddress", GraalRuntime::new_instance); + set_address("newArrayAddress", GraalRuntime::new_array); + set_address("newMultiArrayAddress", GraalRuntime::new_multi_array); + set_address("registerFinalizerAddress", SharedRuntime::register_finalizer); + set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted); + set_address("uncommonTrapStub", SharedRuntime::deopt_blob()->uncommon_trap()); + set_address("vmMessageAddress", GraalRuntime::vm_message); + set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code); + set_address("exceptionHandlerForPcAddress", GraalRuntime::exception_handler_for_pc); + set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address); + set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end); + set_address("monitorenterAddress", GraalRuntime::monitorenter); + set_address("monitorexitAddress", GraalRuntime::monitorexit); + set_address("createNullPointerExceptionAddress", GraalRuntime::create_null_exception); + set_address("createOutOfBoundsExceptionAddress", GraalRuntime::create_out_of_bounds_exception); + set_address("logPrimitiveAddress", GraalRuntime::log_primitive); + set_address("logObjectAddress", GraalRuntime::log_object); + set_address("logPrintfAddress", GraalRuntime::log_printf); + set_address("vmErrorAddress", GraalRuntime::vm_error); + set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre); + set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post); set_int("deoptReasonNone", Deoptimization::Reason_none); set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check); @@ -792,6 +813,7 @@ set_int("deoptReasonJsrMismatch", Deoptimization::Reason_jsr_mismatch); set_int("deoptReasonDiv0Check", Deoptimization::Reason_div0_check); set_int("deoptReasonConstraint", Deoptimization::Reason_constraint); + set_int("deoptReasonLoopLimitCheck", Deoptimization::Reason_loop_limit_check); set_int("deoptActionNone", Deoptimization::Action_none); set_int("deoptActionMaybeRecompile", Deoptimization::Action_maybe_recompile); @@ -849,12 +871,12 @@ ResourceMark rm; HandleMark hm; Handle compResultHandle = JNIHandles::resolve(compResult); - nmethod* nm = NULL; - methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult)); + CodeBlob* cb = NULL; Handle installed_code_handle = JNIHandles::resolve(installed_code); Handle triggered_deoptimizations_handle = JNIHandles::resolve(triggered_deoptimizations); GraalEnv::CodeInstallResult result; - CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle, triggered_deoptimizations_handle); + + CodeInstaller installer(compResultHandle, result, cb, installed_code_handle, triggered_deoptimizations_handle); if (PrintCodeCacheOnCompilation) { stringStream s; @@ -868,13 +890,14 @@ } if (result != GraalEnv::ok) { - assert(nm == NULL, "should be"); + assert(cb == NULL, "should be"); } else { if (!installed_code_handle.is_null()) { assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type"); - HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm); + HotSpotInstalledCode::set_codeBlob(installed_code_handle, (jlong) cb); HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult)); - HotSpotInstalledCode::set_start(installed_code_handle, (jlong) nm->code_begin()); + HotSpotInstalledCode::set_start(installed_code_handle, (jlong) cb->code_begin()); + nmethod* nm = cb->as_nmethod_or_null(); assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable"); } } @@ -886,30 +909,53 @@ method->clear_queued_for_compilation(); C2V_END -C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) +C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject, jlong codeBlob)) + ResourceMark rm; + HandleMark hm; + + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { + return NULL; + } + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + } + int length = cb->code_size(); + arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0); + memcpy(codeCopy->base(T_BYTE), cb->code_begin(), length); + return JNIHandles::make_local(codeCopy); +C2V_END + +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob)) ResourceMark rm; HandleMark hm; - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { return NULL; } - int length = nm->code_size(); - arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0); - memcpy(codeCopy->base(T_BYTE), nm->code_begin(), length); - return JNIHandles::make_local(codeCopy); -C2V_END -C2V_VMENTRY(jobject, disassembleNMethod, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) - ResourceMark rm; - HandleMark hm; - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - return NULL; + // We don't want the stringStream buffer to resize during disassembly as it + // uses scoped resource memory. If a nested function called during disassembly uses + // a ResourceMark and the buffer expands within the scope of the mark, + // the buffer becomes garbage when that scope is exited. Experience shows that + // the disassembled code is typically about 10x the code size so a fixed buffer + // sized to 20x code size should be sufficient. + int bufferSize = cb->code_size() * 20; + char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize); + stringStream st(buffer, bufferSize); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + Disassembler::decode(nm, &st); + } else { + Disassembler::decode(cb, &st); } - stringStream(st); - Disassembler::decode(nm, &st); Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); return JNIHandles::make_local(result()); @@ -924,11 +970,11 @@ return JNIHandles::make_local(element); C2V_END -C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod)) +C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nmethodValue)) ResourceMark rm; HandleMark hm; - nmethod* nm = (nmethod*) (address) nativeMethod; + nmethod* nm = (nmethod*) (address) nmethodValue; methodHandle mh = nm->method(); Symbol* signature = mh->signature(); JavaCallArguments jca(mh->size_of_parameters()); @@ -953,6 +999,7 @@ Method* method = asMethod(metaspace_method); assert(!InstanceKlass::cast(method->method_holder())->is_interface(), "vtableEntryOffset cannot be called for interface methods"); assert(InstanceKlass::cast(method->method_holder())->is_linked(), "vtableEntryOffset cannot be called is holder is not linked"); + assert(method->vtable_index() >= 0, "vtable entry offset should not be used"); // get entry offset in words int vtable_entry_offset = InstanceKlass::vtable_start_offset() + method->vtable_index() * vtableEntry::size(); @@ -962,6 +1009,11 @@ return vtable_entry_offset; C2V_END +C2V_VMENTRY(jboolean, hasVtableEntry, (JNIEnv *, jobject, jlong metaspace_method)) + Method* method = asMethod(metaspace_method); + return method->vtable_index() >= 0; +C2V_END + C2V_VMENTRY(jobject, getDeoptedLeafGraphIds, (JNIEnv *, jobject)) // the contract for this method is as follows: @@ -1129,6 +1181,7 @@ {CC"getInvocationCount", CC"("METASPACE_METHOD")I", FN_PTR(getInvocationCount)}, {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, {CC"getVtableEntryOffset", CC"("METASPACE_METHOD")I", FN_PTR(getVtableEntryOffset)}, + {CC"hasVtableEntry", CC"("METASPACE_METHOD")Z", FN_PTR(hasVtableEntry)}, {CC"constantPoolLength", CC"("HS_RESOLVED_TYPE")I", FN_PTR(constantPoolLength)}, {CC"lookupType", CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE, FN_PTR(lookupType)}, {CC"lookupConstantInPool", CC"("HS_RESOLVED_TYPE"I)"OBJECT, FN_PTR(lookupConstantInPool)}, @@ -1150,7 +1203,7 @@ {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)}, {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I", FN_PTR(installCode0)}, {CC"getCode", CC"(J)[B", FN_PTR(getCode)}, - {CC"disassembleNMethod", CC"(J)"STRING, FN_PTR(disassembleNMethod)}, + {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)}, {CC"executeCompiledMethodVarargs", CC"(["OBJECT NMETHOD")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalJavaAccess.cpp --- a/src/share/vm/graal/graalJavaAccess.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.cpp Mon May 13 17:11:31 2013 +0200 @@ -31,13 +31,8 @@ void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); -#ifndef PRODUCT - if (name_symbol == NULL) { - tty->print_cr("symbol with name %s was not found in symbol table (klass=%s)", name, klass->name()->as_C_string()); - } -#endif if (name_symbol == NULL || signature_symbol == NULL) { - guarantee(false, err_msg("symbol not found - class layout of %s changed?", klass->name()->as_C_string())); + guarantee(false, err_msg("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string())); } InstanceKlass* ik = InstanceKlass::cast(klass); diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Mon May 13 17:11:31 2013 +0200 @@ -58,6 +58,10 @@ long_field(HotSpotResolvedJavaMethod, metaspaceMethod) \ int_field(HotSpotResolvedJavaMethod, codeSize) \ int_field(HotSpotResolvedJavaMethod, exceptionHandlerCount) \ + boolean_field(HotSpotResolvedJavaMethod, callerSensitive) \ + boolean_field(HotSpotResolvedJavaMethod, forceInline) \ + boolean_field(HotSpotResolvedJavaMethod, dontInline) \ + boolean_field(HotSpotResolvedJavaMethod, ignoredBySecurityStackWalk) \ end_class \ start_class(HotSpotMethodData) \ long_field(HotSpotMethodData, metaspaceMethodData) \ @@ -73,7 +77,7 @@ int_field(HotSpotResolvedJavaField, flags) \ end_class \ start_class(HotSpotInstalledCode) \ - long_field(HotSpotInstalledCode, nmethod) \ + long_field(HotSpotInstalledCode, codeBlob) \ oop_field(HotSpotInstalledCode, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ long_field(HotSpotInstalledCode, start) \ boolean_field(HotSpotInstalledCode, isDefault) \ @@ -81,7 +85,7 @@ start_class(HotSpotCompilationResult) \ oop_field(HotSpotCompilationResult, comp, "Lcom/oracle/graal/api/code/CompilationResult;") \ oop_field(HotSpotCompilationResult, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ - oop_field(HotSpotCompilationResult, name, "Ljava/lang/String;") \ + oop_field(HotSpotCompilationResult, stubName, "Ljava/lang/String;") \ int_field(HotSpotCompilationResult, entryBCI) \ oop_field(HotSpotCompilationResult, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;") \ oop_field(HotSpotCompilationResult, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;") \ @@ -162,9 +166,14 @@ oop_field(DebugInfo, bytecodePosition, "Lcom/oracle/graal/api/code/BytecodePosition;") \ oop_field(DebugInfo, registerRefMap, "Ljava/util/BitSet;") \ oop_field(DebugInfo, frameRefMap, "Ljava/util/BitSet;") \ + oop_field(DebugInfo, calleeSaveInfo, "Lcom/oracle/graal/api/code/RegisterSaveLayout;") \ end_class \ - start_class(GraalBitMap) \ - oop_field(GraalBitMap, words, "[J") \ + start_class(RegisterSaveLayout) \ + oop_field(RegisterSaveLayout, registers, "[Lcom/oracle/graal/api/code/Register;") \ + oop_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BitSet) \ + oop_field(BitSet, words, "[J") \ end_class \ start_class(BytecodeFrame) \ oop_field(BytecodeFrame, values, "[Lcom/oracle/graal/api/meta/Value;") \ diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Mon May 13 17:11:31 2013 +0200 @@ -30,44 +30,6 @@ #include "runtime/biasedLocking.hpp" #include "runtime/interfaceSupport.hpp" #include "utilities/debug.hpp" -// Implementation of GraalStubAssembler - -GraalStubAssembler::GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id) : MacroAssembler(code) { - _name = name; - _must_gc_arguments = false; - _frame_size = no_frame_size; - _num_rt_args = 0; - _stub_id = stub_id; -} - - -void GraalStubAssembler::set_info(const char* name, bool must_gc_arguments) { - _name = name; - _must_gc_arguments = must_gc_arguments; -} - - -void GraalStubAssembler::set_frame_size(int size) { - if (_frame_size == no_frame_size) { - _frame_size = size; - } - assert(_frame_size == size, "can't change the frame size"); -} - - -void GraalStubAssembler::set_num_rt_args(int args) { - if (_num_rt_args == 0) { - _num_rt_args = args; - } - assert(_num_rt_args == args, "can't change the number of args"); -} - -// Implementation of GraalRuntime - -CodeBlob* GraalRuntime::_blobs[GraalRuntime::number_of_ids]; -const char *GraalRuntime::_blob_names[] = { - GRAAL_STUBS(STUB_NAME, LAST_STUB_NAME) -}; // Simple helper to see if the caller of a runtime stub which // entered the VM has been deoptimized @@ -93,145 +55,6 @@ } } -static bool setup_code_buffer(CodeBuffer* code) { - // Preinitialize the consts section to some large size: - int locs_buffer_size = 1 * (relocInfo::length_limit + sizeof(relocInfo)); - char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size); - code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, - locs_buffer_size / sizeof(relocInfo)); - - // Global stubs have neither constants nor local stubs - code->initialize_consts_size(0); - code->initialize_stubs_size(0); - - return true; -} - -void GraalRuntime::generate_blob_for(BufferBlob* buffer_blob, StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - ResourceMark rm; - // create code buffer for code storage - CodeBuffer code(buffer_blob); - - setup_code_buffer(&code); - - // create assembler for code generation - GraalStubAssembler* sasm = new GraalStubAssembler(&code, name_for(id), id); - // generate code for runtime stub - OopMapSet* oop_maps; - oop_maps = generate_code_for(id, sasm); - assert(oop_maps == NULL || sasm->frame_size() != GraalStubAssembler::no_frame_size, - "if stub has an oop map it must have a valid frame size"); - -#ifdef ASSERT - // Make sure that stubs that need oopmaps have them - switch (id) { - // These stubs don't need to have an oopmap -#if defined(SPARC) || defined(PPC) - case handle_exception_nofpu_id: // Unused on sparc -#endif - case verify_oop_id: - case unwind_exception_call_id: - case OSR_migration_end_id: - case arithmetic_frem_id: - case arithmetic_drem_id: - break; - // All other stubs should have oopmaps - default: - assert(oop_maps != NULL, "must have an oopmap"); - } -#endif - - // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned) - sasm->align(BytesPerWord); - // make sure all code is in code buffer - sasm->flush(); - // create blob - distinguish a few special cases - CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id), - &code, - CodeOffsets::frame_never_safe, - sasm->frame_size(), - oop_maps, - sasm->must_gc_arguments()); - // install blob - assert(blob != NULL, "blob must exist"); - _blobs[id] = blob; -} - - -void GraalRuntime::initialize(BufferBlob* blob) { - // generate stubs - for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id); - // printing -#ifndef PRODUCT - if (GraalPrintSimpleStubs) { - ResourceMark rm; - for (int id = 0; id < number_of_ids; id++) { - _blobs[id]->print(); - if (_blobs[id]->oop_maps() != NULL) { - _blobs[id]->oop_maps()->print(); - } - } - } -#endif -} - - -CodeBlob* GraalRuntime::blob_for(StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - return _blobs[id]; -} - - -const char* GraalRuntime::name_for(StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - return _blob_names[id]; -} - -const char* GraalRuntime::name_for_address(address entry) { - for (int id = 0; id < number_of_ids; id++) { - if (entry == entry_for((StubID)id)) return name_for((StubID)id); - } - -#define FUNCTION_CASE(a, f) \ - if ((intptr_t)a == CAST_FROM_FN_PTR(intptr_t, f)) return #f - - FUNCTION_CASE(entry, os::javaTimeMillis); - FUNCTION_CASE(entry, os::javaTimeNanos); - FUNCTION_CASE(entry, SharedRuntime::OSR_migration_end); - FUNCTION_CASE(entry, SharedRuntime::d2f); - FUNCTION_CASE(entry, SharedRuntime::d2i); - FUNCTION_CASE(entry, SharedRuntime::d2l); - FUNCTION_CASE(entry, SharedRuntime::dcos); - FUNCTION_CASE(entry, SharedRuntime::dexp); - FUNCTION_CASE(entry, SharedRuntime::dlog); - FUNCTION_CASE(entry, SharedRuntime::dlog10); - FUNCTION_CASE(entry, SharedRuntime::dpow); - FUNCTION_CASE(entry, SharedRuntime::drem); - FUNCTION_CASE(entry, SharedRuntime::dsin); - FUNCTION_CASE(entry, SharedRuntime::dtan); - FUNCTION_CASE(entry, SharedRuntime::f2i); - FUNCTION_CASE(entry, SharedRuntime::f2l); - FUNCTION_CASE(entry, SharedRuntime::frem); - FUNCTION_CASE(entry, SharedRuntime::l2d); - FUNCTION_CASE(entry, SharedRuntime::l2f); - FUNCTION_CASE(entry, SharedRuntime::ldiv); - FUNCTION_CASE(entry, SharedRuntime::lmul); - FUNCTION_CASE(entry, SharedRuntime::lrem); - FUNCTION_CASE(entry, SharedRuntime::lrem); - FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry); - FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit); -#ifdef TRACE_HAVE_INTRINSICS - FUNCTION_CASE(entry, TRACE_TIME_METHOD); -#endif - - ShouldNotReachHere(); - return NULL; - -#undef FUNCTION_CASE -} - - JRT_ENTRY(void, GraalRuntime::new_instance(JavaThread* thread, Klass* klass)) assert(klass->is_klass(), "not a class"); instanceKlassHandle h(thread, klass); @@ -260,11 +83,16 @@ // This is pretty rare but this runtime patch is stressful to deoptimization // if we deoptimize here so force a deopt to stress the path. if (DeoptimizeALot) { - deopt_caller(); + static int deopts = 0; + // Alternate between deoptimizing and raising an error (which will also cause a deopt) + if (deopts++ % 2 == 0) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_OutOfMemoryError()); + } else { + deopt_caller(); + } } - JRT_END - - +JRT_END JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) assert(klass->is_klass(), "not a class"); @@ -273,10 +101,6 @@ thread->set_vm_result(obj); JRT_END -JRT_ENTRY(void, GraalRuntime::unimplemented_entry(JavaThread* thread, StubID id)) - tty->print_cr("GraalRuntime::entry_for(%d) returned unimplemented entry point", id); -JRT_END - extern void vm_exit(int code); // Enter this method from compiled code handler below. This is where we transition @@ -397,7 +221,6 @@ } } - thread->set_vm_result(exception()); // Set flag if return address is a method handle call site. thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); @@ -481,11 +304,11 @@ } JRT_END -JRT_LEAF(void, GraalRuntime::wb_pre_call(JavaThread* thread, oopDesc* obj)) +JRT_LEAF(void, GraalRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) thread->satb_mark_queue().enqueue(obj); JRT_END -JRT_LEAF(void, GraalRuntime::wb_post_call(JavaThread* thread, oopDesc* obj, void* card_addr)) +JRT_LEAF(void, GraalRuntime::write_barrier_post(JavaThread* thread, oopDesc* obj, void* card_addr)) thread->dirty_card_queue().enqueue(card_addr); JRT_END @@ -565,10 +388,44 @@ tty->print(buf, v1, v2, v3); JRT_END -JRT_LEAF(void, GraalRuntime::stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3)) +static void decipher(jlong v, bool ignoreZero) { + if (v != 0 || !ignoreZero) { + void* p = (void *)(address) v; + CodeBlob* cb = CodeCache::find_blob(p); + if (cb) { + if (cb->is_nmethod()) { + char buf[O_BUFLEN]; + tty->print("%s [%p+%d]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), cb->code_begin(), (address)v - cb->code_begin()); + return; + } + cb->print_value_on(tty); + return; + } + if (Universe::heap()->is_in(p)) { + oop obj = oop(p); + obj->print_value_on(tty); + return; + } + tty->print("%p [long: %d, double %f, char %c]", v, v, v, v); + } +} + +JRT_LEAF(void, GraalRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3)) ResourceMark rm; char *buf = (char*) (address) format; - tty->print(buf, v1, v2, v3); + if (vmError) { + if (buf != NULL) { + fatal(err_msg(buf, v1, v2, v3)); + } else { + fatal(""); + } + } else if (buf != NULL) { + tty->print(buf, v1, v2, v3); + } else { + assert(v2 == 0, "v2 != 0"); + assert(v3 == 0, "v3 != 0"); + decipher(v1, false); + } JRT_END JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Mon May 13 17:11:31 2013 +0200 @@ -24,137 +24,26 @@ #ifndef SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP #define SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP -#include "code/stubs.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.hpp" #include "runtime/deoptimization.hpp" -// A GraalStubAssembler is a MacroAssembler w/ extra functionality for runtime -// stubs. Currently it 'knows' some stub info. Eventually, the information -// may be set automatically or can be asserted when using specialised -// GraalStubAssembler functions. - -class GraalStubAssembler: public MacroAssembler { - private: - const char* _name; - bool _must_gc_arguments; - int _frame_size; - int _num_rt_args; - int _stub_id; - +class GraalRuntime: public AllStatic { public: - - enum { - no_frame_size = -1 - }; - - // creation - GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id); - void set_info(const char* name, bool must_gc_arguments); - - void set_frame_size(int size); - void set_num_rt_args(int args); - - // accessors - const char* name() const { return _name; } - bool must_gc_arguments() const { return _must_gc_arguments; } - int frame_size() const { return _frame_size; } - int num_rt_args() const { return _num_rt_args; } - int stub_id() const { return _stub_id; } - - void verify_stack_oop(int offset) PRODUCT_RETURN; - void verify_not_null_oop(Register r) PRODUCT_RETURN; - - // runtime calls (return offset of call to be used by GC map) - int call_RT(Register oop_result1, Register metadata_result, address entry, int args_size = 0); - int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1); - int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2); - int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3); - int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3, Register arg4); -}; - -// set frame size and return address offset to these values in blobs -// (if the compiled frame uses ebp as link pointer on IA; otherwise, -// the frame size must be fixed) - -// Holds all assembly stubs and VM -// runtime routines needed by code code generated -// by Graal. -#define GRAAL_STUBS(stub, last_entry) \ - stub(register_finalizer) \ - stub(new_instance) \ - stub(new_array) \ - stub(new_multi_array) \ - stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ - stub(unwind_exception_call) \ - stub(OSR_migration_end) \ - stub(arithmetic_frem) \ - stub(arithmetic_drem) \ - stub(monitorenter) \ - stub(monitorexit) \ - stub(verify_oop) \ - stub(vm_error) \ - stub(create_null_pointer_exception) \ - stub(create_out_of_bounds_exception) \ - stub(log_object) \ - stub(log_printf) \ - stub(stub_printf) \ - stub(log_primitive) \ - stub(identity_hash_code) \ - stub(thread_is_interrupted) \ - stub(wb_pre_call) \ - stub(wb_post_call) \ - last_entry(number_of_ids) - -#define DECLARE_STUB_ID(x) x ## _id , -#define DECLARE_LAST_STUB_ID(x) x -#define STUB_NAME(x) #x " GraalRuntime stub", -#define LAST_STUB_NAME(x) #x " GraalRuntime stub" - -class GraalRuntime: public AllStatic { - friend class VMStructs; - - public: - enum StubID { - GRAAL_STUBS(DECLARE_STUB_ID, DECLARE_LAST_STUB_ID) - }; - - private: - static CodeBlob* _blobs[number_of_ids]; - static const char* _blob_names[]; - - // stub generation - static void generate_blob_for(BufferBlob* blob, StubID id); - static OopMapSet* generate_code_for(StubID id, GraalStubAssembler* sasm); - static OopMapSet* generate_handle_exception(StubID id, GraalStubAssembler* sasm); - static void generate_unwind_exception(GraalStubAssembler *sasm); - - static OopMapSet* generate_stub_call(GraalStubAssembler* sasm, Register result, address entry, - Register arg1 = noreg, Register arg2 = noreg, Register arg3 = noreg); - - // runtime entry points static void new_instance(JavaThread* thread, Klass* klass); static void new_array(JavaThread* thread, Klass* klass, jint length); static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); - - static void unimplemented_entry(JavaThread* thread, StubID id); - + static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte); + static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); + static jint identity_hash_code(JavaThread* thread, oopDesc* objd); static address exception_handler_for_pc(JavaThread* thread); - - static void create_null_exception(JavaThread* thread); - static void create_out_of_bounds_exception(JavaThread* thread, jint index); static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void create_null_exception(JavaThread* thread); + static void create_out_of_bounds_exception(JavaThread* thread, jint index); static void vm_error(JavaThread* thread, oop where, oop format, jlong value); static void log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3); - static void stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3); static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); - static void wb_pre_call(JavaThread* thread, oopDesc* obj); - static void wb_post_call(JavaThread* thread, oopDesc* obj, void* card); - - static jint identity_hash_code(JavaThread* thread, oopDesc* objd); - static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte); - // Note: Must be kept in sync with constants in com.oracle.graal.replacements.Log enum { LOG_OBJECT_NEWLINE = 0x01, @@ -162,16 +51,8 @@ LOG_OBJECT_ADDRESS = 0x04 }; static void log_object(JavaThread* thread, oop msg, jint flags); - - public: - // initialization - static void initialize(BufferBlob* blob); - - // stubs - static CodeBlob* blob_for (StubID id); - static address entry_for(StubID id) { return blob_for(id)->code_begin(); } - static const char* name_for (StubID id); - static const char* name_for_address(address entry); + static void write_barrier_pre(JavaThread* thread, oopDesc* obj); + static void write_barrier_post(JavaThread* thread, oopDesc* obj, void* card); }; #endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Mon May 13 17:11:31 2013 +0200 @@ -1344,8 +1344,19 @@ // Ensure that we can record deopt. history: bool create_if_missing = ProfileTraps; + methodHandle profiled_method; +#ifdef GRAAL + if (nm->is_compiled_by_graal()) { + profiled_method = nm->method(); + } else { + profiled_method = trap_method; + } +#else + profiled_method = trap_method; +#endif + MethodData* trap_mdo = - get_method_data(thread, trap_method, create_if_missing); + get_method_data(thread, profiled_method, create_if_missing); // Log a message Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d", @@ -1538,7 +1549,6 @@ bool inc_recompile_count = false; ProfileData* pdata = NULL; if (ProfileTraps && update_trap_state && trap_mdo != NULL) { - assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity"); uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Mon May 13 17:11:31 2013 +0200 @@ -3691,6 +3691,9 @@ product(bool , AllowNonVirtualCalls, false, \ "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ \ + product(bool, TraceWarpLoading, false, \ + "trace external GPU warp loading") \ + \ experimental(uintx, ArrayAllocatorMallocLimit, \ SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ "Allocation less than this value will be allocated " \ diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/gpu.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/runtime/gpu.cpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,40 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/gpu.hpp" +#include "ptx/gpu_ptx.hpp" + +bool gpu::_available = false; // does the hardware exist? +bool gpu::_gpu_linkage = false; // is the driver library to access the GPU installed +bool gpu::_initialized = false; // is the GPU defvice initialized + +void gpu::init() { +#ifdef TARGET_OS_FAMILY_bsd + gpu::probe_gpu(); +#endif + // need multi-gpu TARGET ifdef + gpu::probe_linkage(); +} + diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/gpu.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/runtime/gpu.hpp Mon May 13 17:11:31 2013 +0200 @@ -0,0 +1,85 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_RUNTIME_GPU_HPP +#define SHARE_VM_RUNTIME_GPU_HPP + +#include "runtime/atomic.hpp" + +// gpu defines the interface to the graphics processor; this includes traditional +// GPU services such as graphics kernel load and execute. + + +class gpu: AllStatic { +public: + static void init(void); + + static void probe_gpu(); + + static void probe_linkage(); + + static void initialize_gpu(); + + static void generate_kernel(unsigned char *code, int code_len, const char *name); + + static void set_available(bool value) { + _available = value; + } + + static bool is_available() { return _available; } + + static void set_initialized(bool value) { + _initialized = value; + } + + static bool is_initialized() { return _initialized; } + + static void set_gpu_linkage(bool value) { + _gpu_linkage = value; + } + + static bool has_gpu_linkage() { return _gpu_linkage; } + +protected: + static bool _available; + static bool _gpu_linkage; + static bool _initialized; + + // Platform dependent stuff +#ifdef TARGET_OS_FAMILY_linux +#endif +#ifdef TARGET_OS_FAMILY_solaris +#endif +#ifdef TARGET_OS_FAMILY_windows +#endif +#ifdef TARGET_OS_FAMILY_bsd +# include "gpu_bsd.hpp" +#endif + +# include "ptx/gpu_ptx.hpp" + +}; + + +#endif // SHARE_VM_RUNTIME_GPU_HPP diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon May 13 17:11:31 2013 +0200 @@ -484,6 +484,12 @@ // Reset method handle flag. thread->set_is_method_handle_return(false); +#ifdef GRAAL + // Graal's ExceptionHandlerStub expects the thread local exception PC to be clear + // and other exception handler continuations do not read it + thread->set_exception_pc(NULL); +#endif + // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL; diff -r 57113d21ce36 -r f9a65a0e626b src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon May 13 16:46:39 2013 +0200 +++ b/src/share/vm/runtime/thread.cpp Mon May 13 17:11:31 2013 +0200 @@ -54,6 +54,7 @@ #include "runtime/deoptimization.hpp" #include "runtime/fprofiler.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/gpu.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/java.hpp" @@ -3307,6 +3308,9 @@ // Initialize the os module before using TLS os::init(); + // probe for warp capability + gpu::init(); + // Initialize system properties. Arguments::init_system_properties();