# HG changeset patch # User Stefan Anzinger # Date 1427123508 -3600 # Node ID 220c494e50885d4dcb8250a2720b91ff6e470252 # Parent 422e60a2f4b96ceb57ada8a5a0eee2c2847b9bb3# Parent 5aa0cb2914f8c75682ce135bcb3ecc5cbd8a4304 Merge diff -r 422e60a2f4b9 -r 220c494e5088 CHANGELOG.md --- a/CHANGELOG.md Mon Mar 23 15:58:36 2015 +0100 +++ b/CHANGELOG.md Mon Mar 23 16:11:48 2015 +0100 @@ -17,6 +17,8 @@ * Instrumentation: AST "probing" is now safe and implemented by Node.probe(); language implementors need only implement Node.isInstrumentable() and Node.createWrapperNode(). * Instrumentation: A new framework defines a category of simple "instrumentation tools" that can be created, configured, and installed, after which they autonomously collect execution data of some kind. * Instrumentation: A new example "instrumentation tool" is a language-agnostic collector of code coverage information (CoverageTracker); there are two other examples. +* Removed unsafe compiler directives; use `sun.misc.Unsafe` instead. +* Removed `Node#onAdopt()`. ### Truffle-DSL * Implemented a new generated code layout that reduces the code size. diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Mon Mar 23 16:11:48 2015 +0100 @@ -88,7 +88,7 @@ @Override public String toString() { - return name + (isImmutable() ? ":immutable" : ":mutable"); + return name + (isImmutable() ? ":final" : ""); } /** diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Mon Mar 23 16:11:48 2015 +0100 @@ -601,11 +601,14 @@ public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB", P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion); public static final AMD64RMOp MOVSX = new AMD64RMOp("MOVSX", P_0F, 0xBF, OpAssertion.No16BitAssertion); public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD", 0x63, OpAssertion.QwordOnlyAssertion); + public static final AMD64RMOp MOVB = new AMD64RMOp("MOVB", 0x8A, OpAssertion.ByteAssertion); public static final AMD64RMOp MOV = new AMD64RMOp("MOV", 0x8B); - // MOVD and MOVQ are the same opcode, just with different operand size prefix + // MOVD/MOVQ and MOVSS/MOVSD are the same opcode, just with different operand size prefix public static final AMD64RMOp MOVD = new AMD64RMOp("MOVD", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); public static final AMD64RMOp MOVQ = new AMD64RMOp("MOVQ", 0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + public static final AMD64RMOp MOVSS = new AMD64RMOp("MOVSS", P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE); + public static final AMD64RMOp MOVSD = new AMD64RMOp("MOVSD", P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE); // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient. public static final AMD64RMOp TESTB = new AMD64RMOp("TEST", 0x84, OpAssertion.ByteAssertion); @@ -628,6 +631,10 @@ this(opcode, 0, prefix, op, assertion, null); } + protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, 0, prefix, op, assertion, feature); + } + protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) { super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null); } @@ -659,12 +666,17 @@ */ public static class AMD64MROp extends AMD64RROp { // @formatter:off + public static final AMD64MROp MOVB = new AMD64MROp("MOVB", 0x88, OpAssertion.ByteAssertion); public static final AMD64MROp MOV = new AMD64MROp("MOV", 0x89); // MOVD and MOVQ are the same opcode, just with different operand size prefix // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used. public static final AMD64MROp MOVD = new AMD64MROp("MOVD", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); public static final AMD64MROp MOVQ = new AMD64MROp("MOVQ", 0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2); + + // MOVSS and MOVSD are the same opcode, just with different operand size prefix + public static final AMD64MROp MOVSS = new AMD64MROp("MOVSS", P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE); + public static final AMD64MROp MOVSD = new AMD64MROp("MOVSD", P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE); // @formatter:on protected AMD64MROp(String opcode, int op) { @@ -680,7 +692,11 @@ } protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) { - this(opcode, 0, prefix, op, assertion, null); + this(opcode, prefix, op, assertion, null); + } + + protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) { + this(opcode, 0, prefix, op, assertion, feature); } protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) { @@ -747,6 +763,7 @@ */ public static class AMD64MIOp extends AMD64ImmOp { // @formatter:off + public static final AMD64MIOp MOVB = new AMD64MIOp("MOVB", true, 0xC6, 0, OpAssertion.ByteAssertion); public static final AMD64MIOp MOV = new AMD64MIOp("MOV", false, 0xC7, 0); public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0); // @formatter:on @@ -754,7 +771,11 @@ private final int ext; protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) { - this(opcode, immIsByte, 0, op, ext, OpAssertion.IntegerAssertion); + this(opcode, immIsByte, op, ext, OpAssertion.IntegerAssertion); + } + + protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext, OpAssertion assertion) { + this(opcode, immIsByte, 0, op, ext, assertion); } protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) { diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon Mar 23 16:11:48 2015 +0100 @@ -50,7 +50,6 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; -import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.*; @@ -68,7 +67,6 @@ import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; -import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp; import com.oracle.graal.lir.gen.*; import com.oracle.graal.phases.util.*; @@ -107,28 +105,6 @@ } } - /** - * Checks whether the supplied constant can be used without loading it into a register for store - * operations, i.e., on the right hand side of a memory access. - * - * @param c The constant to check. - * @return True if the constant can be used directly, false if the constant needs to be in a - * register. - */ - protected boolean canStoreConstant(JavaConstant c) { - // there is no immediate move of 64-bit constants on Intel - switch (c.getKind()) { - case Long: - return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); - case Double: - return false; - case Object: - return c.isNull(); - default: - return true; - } - } - protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { if (src instanceof AMD64AddressValue) { return new LeaOp(dst, (AMD64AddressValue) src); @@ -290,14 +266,14 @@ private void emitIntegerTest(Value a, Value b) { assert a.getKind().isNumericInteger(); OperandSize size = a.getKind() == Kind.Long ? QWORD : DWORD; - if (isConstant(b)) { - append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(a), asConstant(b))); - } else if (isConstant(a)) { - append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(b), asConstant(a))); + if (isConstant(b) && NumUtil.is32bit(asConstant(b).asLong())) { + append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asConstant(b).asLong())); + } else if (isConstant(a) && NumUtil.is32bit(asConstant(a).asLong())) { + append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asConstant(a).asLong())); } else if (isAllocatableValue(b)) { - append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a))); + append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a))); } else { - append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b))); + append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b))); } } @@ -320,10 +296,10 @@ size = QWORD; break; case Float: - append(new AMD64CompareOp(SSEOp.UCOMIS, PS, left, asAllocatable(right))); + append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, asAllocatable(right))); return; case Double: - append(new AMD64CompareOp(SSEOp.UCOMIS, PD, left, asAllocatable(right))); + append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, asAllocatable(right))); return; default: throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind); @@ -333,17 +309,16 @@ JavaConstant c = asConstant(right); if (c.isDefaultForKind()) { AMD64RMOp op = size == BYTE ? TESTB : TEST; - append(new AMD64CompareOp(op, size, left, left)); + append(new AMD64BinaryConsumer.Op(op, size, left, left)); return; } else if (NumUtil.is32bit(c.asLong())) { - AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(c.asLong())); - append(new AMD64CompareConstOp(op, size, left, c)); + append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) c.asLong())); return; } } AMD64RMOp op = CMP.getRMOpcode(size); - append(new AMD64CompareOp(op, size, left, asAllocatable(right))); + append(new AMD64BinaryConsumer.Op(op, size, left, asAllocatable(right))); } /** @@ -372,10 +347,10 @@ size = QWORD; break; case Float: - append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state)); + append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state)); return false; case Double: - append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state)); + append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state)); return false; default: throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind); @@ -390,8 +365,7 @@ protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) { if (NumUtil.is32bit(a.asLong())) { - AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(a.asLong())); - append(new AMD64CompareMemoryConstOp(op, size, b, a, state)); + append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) a.asLong(), state)); return true; } else { return emitCompareRegMemoryOp(size, a, b, state); @@ -400,7 +374,7 @@ private boolean emitCompareRegMemoryOp(OperandSize size, Value a, AMD64AddressValue b, LIRFrameState state) { AMD64RMOp op = CMP.getRMOpcode(size); - append(new AMD64CompareMemoryOp(op, size, asAllocatable(a), b, state)); + append(new AMD64BinaryConsumer.MemoryRMOp(op, size, asAllocatable(a), b, state)); return false; } @@ -435,16 +409,16 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Int: - append(new AMD64UnaryMOp(NEG, DWORD, result, input)); + append(new AMD64Unary.MOp(NEG, DWORD, result, input)); break; case Long: - append(new AMD64UnaryMOp(NEG, QWORD, result, input)); + append(new AMD64Unary.MOp(NEG, QWORD, result, input)); break; case Float: - append(new AMD64BinaryPatchOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); + append(new AMD64Binary.DataOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); break; case Double: - append(new AMD64BinaryPatchOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); + append(new AMD64Binary.DataOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -458,10 +432,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Int: - append(new AMD64UnaryMOp(NOT, DWORD, result, input)); + append(new AMD64Unary.MOp(NOT, DWORD, result, input)); break; case Long: - append(new AMD64UnaryMOp(NOT, QWORD, result, input)); + append(new AMD64Unary.MOp(NOT, QWORD, result, input)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -492,7 +466,7 @@ private Variable emitBinaryConst(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b) { if (NumUtil.isInt(b.asLong())) { Variable result = newVariable(LIRKind.derive(a, b)); - append(new AMD64BinaryConstOp(op, size, result, a, b)); + append(new AMD64Binary.ConstOp(op, size, result, a, (int) b.asLong())); return result; } else { return emitBinaryVar(op.getRMOpcode(size), size, commutative, a, asAllocatable(b)); @@ -501,16 +475,16 @@ private Variable emitBinaryConst(AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) { Variable result = newVariable(LIRKind.derive(a, b)); - append(new AMD64BinaryPatchOp(op, size, result, a, b)); + append(new AMD64Binary.DataOp(op, size, result, a, b)); return result; } private Variable emitBinaryVar(AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) { Variable result = newVariable(LIRKind.derive(a, b)); if (commutative) { - append(new AMD64BinaryCommutativeOp(op, size, result, a, b)); + append(new AMD64Binary.CommutativeOp(op, size, result, a, b)); } else { - append(new AMD64BinaryOp(op, size, result, a, b)); + append(new AMD64Binary.Op(op, size, result, a, b)); } return result; } @@ -558,7 +532,7 @@ } Variable ret = newVariable(LIRKind.derive(a, b)); - append(new AMD64MulConstOp(op, size, ret, a, b)); + append(new AMD64Binary.RMIOp(op, size, ret, a, imm)); return ret; } else { return emitBinaryVar(AMD64RMOp.IMUL, size, true, a, asAllocatable(b)); @@ -628,13 +602,13 @@ public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { Variable result = newVariable(LIRKind.derive(a)); - append(new AMD64BinaryMemoryOp(op, size, result, a, location, state)); + append(new AMD64Binary.MemoryOp(op, size, result, a, location, state)); return result; } protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) { Variable result = newVariable(LIRKind.value(kind)); - append(new AMD64UnaryMemoryOp(op, size, result, address, state)); + append(new AMD64Unary.MemoryOp(op, size, result, address, state)); return result; } @@ -642,7 +616,24 @@ // Issue a zero extending load of the proper bit size and set the result to // the proper kind. Variable result = newVariable(LIRKind.value(resultBits == 32 ? Kind.Int : Kind.Long)); - append(new ZeroExtendLoadOp(memoryKind, result, address, state)); + switch (memoryKind) { + case Boolean: + case Byte: + append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state)); + break; + case Char: + case Short: + append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state)); + break; + case Int: + append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state)); + break; + case Long: + append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } return result; } @@ -805,9 +796,13 @@ if (isConstant(b)) { JavaConstant c = asConstant(b); if (c.asLong() == 1) { - append(new AMD64UnaryMOp(op.m1Op, size, result, input)); + append(new AMD64Unary.MOp(op.m1Op, size, result, input)); } else { - append(new AMD64BinaryConstOp(op.miOp, size, result, input, c)); + /* + * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is + * always correct, even without the NumUtil.is32bit() test. + */ + append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong())); } } else { emitMove(RCX_I, b); @@ -876,13 +871,13 @@ private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) { Variable result = newVariable(kind); - append(new AMD64UnaryRMOp(op, size, result, asAllocatable(input))); + append(new AMD64Unary.RMOp(op, size, result, asAllocatable(input))); return result; } private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) { Variable result = newVariable(kind); - append(new AMD64UnaryMROp(op, size, result, asAllocatable(input))); + append(new AMD64Unary.MROp(op, size, result, asAllocatable(input))); return result; } @@ -1006,13 +1001,13 @@ assert inputVal.getKind() == Kind.Long; Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); long mask = CodeUtil.mask(fromBits); - append(new AMD64BinaryPatchOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); + append(new AMD64Binary.DataOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); return result; } else { assert inputVal.getKind().getStackKind() == Kind.Int; Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); int mask = (int) CodeUtil.mask(fromBits); - append(new AMD64BinaryPatchOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); + append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); if (toBits > 32) { Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); emitMove(longResult, result); @@ -1047,9 +1042,9 @@ public Variable emitBitCount(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64UnaryRMOp(POPCNT, DWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(POPCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64UnaryRMOp(POPCNT, QWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(POPCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1057,7 +1052,7 @@ @Override public Variable emitBitScanForward(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); - append(new AMD64UnaryRMOp(BSF, QWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(BSF, QWORD, result, asAllocatable(value))); return result; } @@ -1065,9 +1060,9 @@ public Variable emitBitScanReverse(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64UnaryRMOp(BSR, DWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(BSR, DWORD, result, asAllocatable(value))); } else { - append(new AMD64UnaryRMOp(BSR, QWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(BSR, QWORD, result, asAllocatable(value))); } return result; } @@ -1075,9 +1070,9 @@ public Value emitCountLeadingZeros(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64UnaryRMOp(LZCNT, DWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(LZCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64UnaryRMOp(LZCNT, QWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(LZCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1085,9 +1080,9 @@ public Value emitCountTrailingZeros(Value value) { Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64UnaryRMOp(TZCNT, DWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(TZCNT, DWORD, result, asAllocatable(value))); } else { - append(new AMD64UnaryRMOp(TZCNT, QWORD, result, asAllocatable(value))); + append(new AMD64Unary.RMOp(TZCNT, QWORD, result, asAllocatable(value))); } return result; } @@ -1097,10 +1092,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Float: - append(new AMD64BinaryPatchOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16)); + append(new AMD64Binary.DataOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16)); break; case Double: - append(new AMD64BinaryPatchOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16)); + append(new AMD64Binary.DataOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -1113,10 +1108,10 @@ Variable result = newVariable(LIRKind.derive(input)); switch (input.getKind()) { case Float: - append(new AMD64UnaryRMOp(SSEOp.SQRT, SS, result, asAllocatable(input))); + append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, asAllocatable(input))); break; case Double: - append(new AMD64UnaryRMOp(SSEOp.SQRT, SD, result, asAllocatable(input))); + append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, asAllocatable(input))); break; default: throw GraalInternalError.shouldNotReachHere(); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Mon Mar 23 16:11:48 2015 +0100 @@ -214,13 +214,13 @@ return null; } return builder -> { - gen.append(new AMD64CompareMemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), constant, getState(access))); + gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), (int) constant.asLong(), getState(access))); gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); return null; }; } else { return builder -> { - gen.append(new AMD64CompareMemoryOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access))); + gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access))); gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); return null; }; diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Mar 23 16:11:48 2015 +0100 @@ -46,7 +46,6 @@ import com.oracle.graal.lir.phases.*; import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; -import com.oracle.graal.lir.profiling.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Mon Mar 23 16:11:48 2015 +0100 @@ -37,9 +37,11 @@ */ public class Graph { - static class Options { + public static class Options { @Option(help = "Verify graphs often during compilation when assertions are turned on", type = OptionType.Debug)// public static final OptionValue VerifyGraalGraphs = new OptionValue<>(true); + @Option(help = "Perform expensive verification of graph inputs, usages, successors and predecessors", type = OptionType.Debug)// + public static final OptionValue VerifyGraalGraphEdges = new OptionValue<>(false); } public final String name; diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Mar 23 16:11:48 2015 +0100 @@ -847,9 +847,30 @@ protected void afterClone(@SuppressWarnings("unused") Node other) { } + public boolean verifyInputs() { + for (Node input : inputs()) { + assertFalse(input.isDeleted(), "input was deleted"); + assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); + } + return true; + } + public boolean verify() { assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id); assertTrue(graph() != null, "null graph"); + if (Options.VerifyGraalGraphEdges.getValue()) { + verifyEdges(); + } + return true; + } + + /** + * Perform expensive verification of inputs, usages, predecessors and successors. + * + * @return true + */ + public boolean verifyEdges() { + verifyInputs(); for (Node input : inputs()) { assertTrue(input.usages().contains(this), "missing usage in input %s", input); } @@ -864,7 +885,7 @@ while (iterator.hasNext()) { Position pos = iterator.nextPosition(); if (pos.get(usage) == this && pos.getInputType() != InputType.Unchecked) { - assert isAllowedUsageType(pos.getInputType()) : "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")"; + assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")"); } } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Mon Mar 23 16:11:48 2015 +0100 @@ -335,8 +335,12 @@ @Override @SuppressWarnings("unchecked") - public A[] toArray(A[] template) { - return (A[]) Arrays.copyOf(nodes, size, template.getClass()); + public A[] toArray(A[] a) { + if (a.length >= size) { + System.arraycopy(nodes, 0, a, 0, size); + return a; + } + return (A[]) Arrays.copyOf(nodes, size, a.getClass()); } @Override diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Mon Mar 23 16:11:48 2015 +0100 @@ -168,7 +168,7 @@ * {@link InvocationPlugins} in the copy. */ public GraphBuilderConfiguration copy() { - Plugins newPlugins = new Plugins(new InvocationPlugins(plugins.getInvocationPlugins())); + Plugins newPlugins = new Plugins(plugins); GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins); result.useProfiling = useProfiling; return result; diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Mon Mar 23 16:11:48 2015 +0100 @@ -26,7 +26,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; /** @@ -60,15 +59,15 @@ boolean isIntrinsic(); } - T append(T fixed); - - T append(T fixed); + T append(T value); - T append(T fixed); - - T append(T value); - - T append(T value); + /** + * Adds the given floating node to the graph and also adds recursively all referenced inputs. + * + * @param value the floating node to be added to the graph + * @return either the node added or an equivalent node + */ + T recursiveAppend(T value); StampProvider getStampProvider(); @@ -125,17 +124,6 @@ */ Replacement getReplacement(); - /** - * @see GuardingPiNode#nullCheckedValue(ValueNode) - */ - static ValueNode nullCheckedValue(GraphBuilderContext builder, ValueNode value) { - ValueNode nonNullValue = GuardingPiNode.nullCheckedValue(value); - if (nonNullValue != value) { - builder.append((FixedWithNextNode) nonNullValue); - } - return nonNullValue; - } - boolean eagerResolving(); BailoutException bailout(String string); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java Mon Mar 23 16:11:48 2015 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; import com.oracle.graal.nodes.*; /** @@ -36,43 +37,43 @@ /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { - throw invalidHandler(b, targetMethod); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + throw invalidHandler(b, targetMethod, receiver); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { - throw invalidHandler(b, targetMethod, arg); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + throw invalidHandler(b, targetMethod, receiver, arg); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) { - throw invalidHandler(b, targetMethod, arg1, arg2); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4); } /** * @see #execute */ - default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { - throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5); + default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { + throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5); } default ResolvedJavaMethod getSubstitute() { @@ -84,30 +85,52 @@ * {@code apply(...)} method that matches the number of arguments. * * @param targetMethod the method for which plugin is being applied + * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static + * @param args the remaining arguments * @return {@code true} if the plugin handled the invocation of {@code targetMethod} * {@code false} if the graph builder should process the invoke further (e.g., by * inlining it or creating an {@link Invoke} node). A plugin that does not handle an * invocation must not modify the graph being constructed. */ - static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) { - if (args.length == 0) { - return plugin.apply(b, targetMethod); - } else if (args.length == 1) { - return plugin.apply(b, targetMethod, args[0]); - } else if (args.length == 2) { - return plugin.apply(b, targetMethod, args[0], args[1]); - } else if (args.length == 3) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2]); - } else if (args.length == 4) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]); - } else if (args.length == 5) { - return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]); + static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] args) { + if (receiver != null) { + assert !targetMethod.isStatic(); + assert args.length > 0; + if (args.length == 1) { + return plugin.apply(b, targetMethod, receiver); + } else if (args.length == 2) { + return plugin.apply(b, targetMethod, receiver, args[1]); + } else if (args.length == 3) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2]); + } else if (args.length == 4) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3]); + } else if (args.length == 5) { + return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3], args[4]); + } else { + throw plugin.invalidHandler(b, targetMethod, receiver, args); + } } else { - throw plugin.invalidHandler(b, targetMethod, args); + assert targetMethod.isStatic(); + if (args.length == 0) { + return plugin.apply(b, targetMethod, null); + } else if (args.length == 1) { + return plugin.apply(b, targetMethod, null, args[0]); + } else if (args.length == 2) { + return plugin.apply(b, targetMethod, null, args[0], args[1]); + } else if (args.length == 3) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2]); + } else if (args.length == 4) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3]); + } else if (args.length == 5) { + return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3], args[4]); + } else { + throw plugin.invalidHandler(b, targetMethod, receiver, args); + } + } } - default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) { + default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) { return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length); } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Mon Mar 23 16:11:48 2015 +0100 @@ -30,7 +30,10 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; /** * Manages a set of {@link InvocationPlugin}s. @@ -38,14 +41,24 @@ public class InvocationPlugins { /** - * Sentinel class for use with + * Access to the receiver in an {@link InvocationPlugin} for a non-static method. The class + * literal for this interface must be used with * {@link InvocationPlugins#register(InvocationPlugin, Class, String, Class...)} to denote the - * receiver argument for a non-static method. + * receiver argument for such a non-static method. */ - public static final class Receiver { - private Receiver() { - throw GraalInternalError.shouldNotReachHere(); - } + public interface Receiver { + /** + * Gets the receiver value, null checking it first if necessary. + * + * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode) + * non-null} stamp + */ + ValueNode get(); + + /** + * Determines if the receiver is constant. + */ + boolean isConstant(); } /** @@ -342,11 +355,12 @@ Class[] sig = method.getParameterTypes(); assert sig[0] == GraphBuilderContext.class; assert sig[1] == ResolvedJavaMethod.class; - assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class); - while (sigs.size() < sig.length - 1) { + assert sig[2] == Receiver.class; + assert Arrays.asList(Arrays.copyOfRange(sig, 3, sig.length)).stream().allMatch(c -> c == ValueNode.class); + while (sigs.size() < sig.length - 2) { sigs.add(null); } - sigs.set(sig.length - 2, sig); + sigs.set(sig.length - 3, sig); } } assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null), @@ -360,7 +374,7 @@ assert !p.registrations.contains(method) : "a plugin is already registered for " + method; p = p.parent; } - int arguments = method.argumentTypes.length; + int arguments = method.isStatic ? method.argumentTypes.length : method.argumentTypes.length - 1; assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method); for (Method m : plugin.getClass().getDeclaredMethods()) { if (m.getName().equals("apply")) { @@ -381,4 +395,18 @@ public int size() { return registrations.size(); } + + /** + * Checks a set of nodes added to the graph by an {@link InvocationPlugin}. + * + * @param b the graph builder that applied the plugin + * @param plugin a plugin that was just applied + * @param newNodes the nodes added to the graph by {@code plugin} + * @throws AssertionError if any check fail + */ + public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { + if (parent != null) { + parent.checkNewNodes(b, plugin, newNodes); + } + } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBinaryConsumer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBinaryConsumer.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.amd64; + +import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +public class AMD64HotSpotBinaryConsumer { + + /** + * Instruction that has one {@link AllocatableValue} operand and one {@link HotSpotConstant} + * operand. + */ + public static class ConstOp extends AMD64BinaryConsumer.ConstOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstOp.class); + + protected final HotSpotConstant c; + + public ConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant c) { + super(TYPE, opcode, DWORD, x, asImm32(c)); + this.c = c; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert crb.target.inlineObjects || !(c instanceof HotSpotObjectConstant); + crb.recordInlineDataInCode(c); + super.emitCode(crb, masm); + } + } + + /** + * Instruction that has one {@link AMD64AddressValue memory} operand and one + * {@link HotSpotConstant} operand. + */ + public static class MemoryConstOp extends AMD64BinaryConsumer.MemoryConstOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryConstOp.class); + + protected final HotSpotConstant c; + + public MemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant c, LIRFrameState state) { + super(TYPE, opcode, DWORD, x, asImm32(c), state); + this.c = c; + + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + assert crb.target.inlineObjects || !(c instanceof HotSpotObjectConstant); + crb.recordInlineDataInCode(c); + super.emitCode(crb, masm); + } + } + + private static int asImm32(HotSpotConstant c) { + assert c.isCompressed(); + if (c instanceof HotSpotMetaspaceConstant) { + return (int) ((HotSpotMetaspaceConstant) c).rawValue(); + } else { + assert c instanceof HotSpotObjectConstant; + return 0xDEADDEAD; + } + } +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64HotSpotCompareConstOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCompareConstOp.class); - - @Opcode private final AMD64MIOp opcode; - - @Use({REG, STACK}) protected AllocatableValue x; - protected HotSpotConstant y; - - public AMD64HotSpotCompareConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant y) { - super(TYPE); - this.opcode = opcode; - this.x = x; - this.y = y; - - assert y.isCompressed(); - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - int imm32; - if (y instanceof HotSpotMetaspaceConstant) { - imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue(); - } else { - assert y instanceof HotSpotObjectConstant; - imm32 = 0xDEADDEAD; - } - - crb.recordInlineDataInCode(y); - if (isRegister(x)) { - opcode.emit(masm, DWORD, asRegister(x), imm32); - } else { - assert isStackSlot(x); - opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64HotSpotCompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotCompareMemoryConstOp.class); - - @Opcode private final AMD64MIOp opcode; - - @Use({COMPOSITE}) protected AMD64AddressValue x; - protected HotSpotConstant y; - - @State protected LIRFrameState state; - - public AMD64HotSpotCompareMemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant y, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.x = x; - this.y = y; - this.state = state; - - assert y.isCompressed(); - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - int imm32; - if (y instanceof HotSpotMetaspaceConstant) { - imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue(); - } else { - assert y instanceof HotSpotObjectConstant; - imm32 = 0xDEADDEAD; - } - - crb.recordInlineDataInCode(y); - if (isRegister(x)) { - opcode.emit(masm, DWORD, asRegister(x), imm32); - } else { - assert isStackSlot(x); - opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32); - } - } - - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { - state = nullCheckState; - return true; - } - return false; - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.amd64; - -import static com.oracle.graal.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.asm.amd64.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64HotSpotComparePatchOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotComparePatchOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Use({REG}) protected AllocatableValue x; - protected HotSpotConstant y; - - public AMD64HotSpotComparePatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, HotSpotConstant y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(y, size.getBytes()); - opcode.emit(masm, size, asRegister(x), addr); - } -} diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Mar 23 16:11:48 2015 +0100 @@ -34,6 +34,9 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.*; @@ -42,7 +45,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding; -import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp; import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.stubs.*; @@ -53,9 +55,7 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; -import com.oracle.graal.lir.amd64.AMD64Move.LoadOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; -import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.lir.gen.*; @@ -506,22 +506,137 @@ public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { AMD64AddressValue loadAddress = asAddressValue(address); Variable result = newVariable(toStackKind(kind)); - append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state)); + switch ((Kind) kind.getPlatformKind()) { + case Boolean: + append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); + break; + case Byte: + append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); + break; + case Char: + append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); + break; + case Short: + append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); + break; + case Int: + append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); + break; + case Long: + case Object: + append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); + break; + case Float: + append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); + break; + case Double: + append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } return result; } + private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { + if (value.isNull()) { + assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; + OperandSize size = kind == Kind.Int ? DWORD : QWORD; + append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); + } else if (value instanceof HotSpotConstant) { + HotSpotConstant c = (HotSpotConstant) value; + if (c.isCompressed()) { + assert kind == Kind.Int; + if (!target().inlineObjects && c instanceof HotSpotObjectConstant) { + emitStore(kind, address, asAllocatable(value), state); + } else { + append(new AMD64HotSpotBinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, address, c, state)); + } + } else { + emitStore(kind, address, asAllocatable(value), state); + } + } else { + AMD64MIOp op = AMD64MIOp.MOV; + OperandSize size; + long imm; + + switch (kind) { + case Boolean: + case Byte: + op = AMD64MIOp.MOVB; + size = BYTE; + imm = value.asInt(); + break; + case Char: + case Short: + size = WORD; + imm = value.asInt(); + break; + case Int: + size = DWORD; + imm = value.asInt(); + break; + case Long: + size = QWORD; + imm = value.asLong(); + break; + case Float: + size = DWORD; + imm = Float.floatToRawIntBits(value.asFloat()); + break; + case Double: + size = QWORD; + imm = Double.doubleToRawLongBits(value.asDouble()); + break; + default: + throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind); + } + + if (NumUtil.isInt(imm)) { + append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); + } else { + emitStore(kind, address, asAllocatable(value), state); + } + } + } + + private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { + switch (kind) { + case Boolean: + case Byte: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); + break; + case Char: + case Short: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); + break; + case Int: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); + break; + case Long: + case Object: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); + break; + case Float: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); + break; + case Double: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + @Override - public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) { + public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { AMD64AddressValue storeAddress = asAddressValue(address); - if (isConstant(inputVal)) { - JavaConstant c = asConstant(inputVal); - if (canStoreConstant(c)) { - append(new HotSpotStoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state)); - return; - } + Kind kind = (Kind) lirKind.getPlatformKind(); + if (isConstant(input)) { + emitStoreConst(kind, storeAddress, asConstant(input), state); + } else { + emitStore(kind, storeAddress, asAllocatable(input), state); } - Variable input = load(inputVal); - append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state)); } @Override @@ -628,17 +743,17 @@ @Override protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) { if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(right)) { - append(new AMD64CompareOp(TEST, DWORD, left, left)); + append(new AMD64BinaryConsumer.Op(TEST, DWORD, left, left)); } else if (right instanceof HotSpotConstant) { HotSpotConstant c = (HotSpotConstant) right; boolean isImmutable = GraalOptions.ImmutableCode.getValue(); boolean generatePIC = GraalOptions.GeneratePIC.getValue(); if (c.isCompressed() && !(isImmutable && generatePIC)) { - append(new AMD64HotSpotCompareConstOp(CMP.getMIOpcode(DWORD, false), left, c)); + append(new AMD64HotSpotBinaryConsumer.ConstOp(CMP.getMIOpcode(DWORD, false), left, c)); } else { OperandSize size = c.isCompressed() ? DWORD : QWORD; - append(new AMD64HotSpotComparePatchOp(CMP.getRMOpcode(size), size, left, c)); + append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, c)); } } else { super.emitCompareOp(cmpKind, left, right); @@ -648,11 +763,11 @@ @Override protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) { if (a.isNull()) { - append(new AMD64CompareMemoryConstOp(CMP.getMIOpcode(size, true), size, b, PrimitiveConstant.INT_0, state)); + append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state)); return true; } else if (a instanceof HotSpotConstant && size == DWORD) { assert ((HotSpotConstant) a).isCompressed(); - append(new AMD64HotSpotCompareMemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state)); + append(new AMD64HotSpotBinaryConsumer.MemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state)); return true; } else { return super.emitCompareMemoryConOp(size, a, b, state); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java Mon Mar 23 16:11:48 2015 +0100 @@ -38,7 +38,6 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; import com.oracle.graal.lir.asm.*; public class AMD64HotSpotMove { @@ -146,44 +145,6 @@ } } - public static class HotSpotStoreConstantOp extends StoreConstantOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(HotSpotStoreConstantOp.class); - - public HotSpotStoreConstantOp(Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) { - super(TYPE, kind, address, input, state); - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (input.isNull() && kind == Kind.Int) { - // compressed null - masm.movl(address.toAddress(), 0); - } else if (input instanceof HotSpotObjectConstant) { - HotSpotObjectConstant c = (HotSpotObjectConstant) input; - if (c.isCompressed() && crb.target.inlineObjects) { - // compressed oop - crb.recordInlineDataInCode(input); - masm.movl(address.toAddress(), 0xDEADDEAD); - } else { - // uncompressed oop - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - } else if (input instanceof HotSpotMetaspaceConstant) { - if (input.getKind() == Kind.Int) { - // compressed metaspace pointer - crb.recordInlineDataInCode(input); - masm.movl(address.toAddress(), input.asInt()); - } else { - // uncompressed metaspace pointer - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - } else { - // primitive value - super.emitMemAccess(crb, masm); - } - } - } - public static final class CompressPointer extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.test; -import static com.oracle.graal.nodes.spi.Replacements.*; - import java.io.*; import java.lang.reflect.*; import java.security.*; @@ -34,10 +32,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; +import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.*; +import com.oracle.graal.phases.*; /** * Tests the intrinsification of certain crypto methods. @@ -58,44 +62,51 @@ return installedCode; } - @Test - public void testEncryptSubstitution() throws Exception { - Assume.assumeTrue(SELF_RECURSIVE_INTRINSICS_ENABLED); + SecretKey aesKey; + SecretKey desKey; + byte[] input; + ByteArrayOutputStream aesExpected = new ByteArrayOutputStream(); + ByteArrayOutputStream desExpected = new ByteArrayOutputStream(); + public HotSpotCryptoSubstitutionTest() throws Exception { byte[] seed = {0x4, 0x7, 0x1, 0x1}; SecureRandom random = new SecureRandom(seed); KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES"); KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede"); aesKeyGen.init(128, random); desKeyGen.init(168, random); - SecretKey aesKey = aesKeyGen.generateKey(); - SecretKey desKey = desKeyGen.generateKey(); - byte[] input = readClassfile16(getClass()); + aesKey = aesKeyGen.generateKey(); + desKey = desKeyGen.generateKey(); + input = readClassfile16(getClass()); + + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); - ByteArrayOutputStream aesExpected = new ByteArrayOutputStream(); - aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); + } + @Test + public void testAESCryptIntrinsics() throws Exception { if (compileAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) { ByteArrayOutputStream actual = new ByteArrayOutputStream(); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); } + } - ByteArrayOutputStream desExpected = new ByteArrayOutputStream(); - desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input)); - desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input)); - + @Test + public void testCipherBlockChainingIntrinsics() throws Exception { if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) { ByteArrayOutputStream actual = new ByteArrayOutputStream(); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding")); + actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding")); Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray()); actual.reset(); - actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input)); - actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input)); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding")); + actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding")); Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray()); } } @@ -114,9 +125,13 @@ Method method = lookup(className, methodName); if (method != null) { ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method); - StructuredGraph subst = getReplacements().getMethodSubstitution(installedCodeOwner); - if (subst != null) { - StructuredGraph graph = subst.copy(); + ResolvedJavaMethod substMethod = getReplacements().getMethodSubstitutionMethod(installedCodeOwner); + if (substMethod != null) { + StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES); + Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins()); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, -2); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); Assert.assertNotNull(getCode(installedCodeOwner, graph, true)); atLeastOneCompiled = true; } else { @@ -191,7 +206,7 @@ return classFile; } - public byte[] runEncryptDecrypt(SecretKey key, String algorithm, byte[] input) throws Exception { + public byte[] runEncryptDecrypt(SecretKey key, String algorithm) throws Exception { byte[] indata = input.clone(); byte[] cipher = encrypt(indata, key, algorithm); byte[] plain = decrypt(cipher, key, algorithm); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon Mar 23 16:11:48 2015 +0100 @@ -290,7 +290,7 @@ final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes); // Log a compilation event. - if (compilationEvent.shouldWrite()) { + if (compilationEvent.shouldWrite() && installedCode != null) { compilationEvent.setMethod(method.format("%H.%n(%p)")); compilationEvent.setCompileId(getId()); compilationEvent.setCompileLevel(config.compilationLevelFullOptimization); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon Mar 23 16:11:48 2015 +0100 @@ -31,16 +31,21 @@ import java.lang.reflect.*; import java.net.*; import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; import java.util.jar.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.bytecode.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess; import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.options.*; import com.oracle.graal.options.OptionUtils.OptionConsumer; import com.oracle.graal.options.OptionValue.OverrideScope; +import com.oracle.graal.printer.*; import com.oracle.graal.replacements.*; /** @@ -69,6 +74,9 @@ "to disable inlining and partial escape analysis specify '-PartialEscapeAnalysis -Inline'. " + "The format for each option is the same as on the command line just without the '-G:' prefix.", type = OptionType.Debug) public static final OptionValue CompileTheWorldConfig = new OptionValue<>(null); + + @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug) + public static final OptionValue CompileTheWorldMultiThreaded = new OptionValue<>(false); // @formatter:on /** @@ -98,9 +106,7 @@ * */ @SuppressWarnings("serial") - public static class Config extends HashMap, Object> implements AutoCloseable, OptionConsumer { - OverrideScope scope; - + public static class Config extends HashMap, Object> implements OptionConsumer { /** * Creates a {@link Config} object by parsing a set of space separated override options. * @@ -120,20 +126,10 @@ /** * Applies the overrides represented by this object. The overrides are in effect until - * {@link #close()} is called on this object. + * {@link OverrideScope#close()} is called on the returned object. */ - Config apply() { - assert scope == null; - scope = OptionValue.override(this); - return this; - } - - public void close() { - assert scope != null; - scope.close(); - - scope = null; - + OverrideScope apply() { + return OptionValue.override(this); } public void set(OptionDescriptor desc, Object value) { @@ -155,13 +151,15 @@ // Counters private int classFileCounter = 0; - private int compiledMethodsCounter = 0; - private long compileTime = 0; - private long memoryUsed = 0; + private AtomicLong compiledMethodsCounter = new AtomicLong(); + private AtomicLong compileTime = new AtomicLong(); + private AtomicLong memoryUsed = new AtomicLong(); private boolean verbose; private final Config config; + private ThreadPoolExecutor threadPool; + /** * Creates a compile-the-world instance. * @@ -177,11 +175,11 @@ this.config = config; // We don't want the VM to exit when a method fails to compile... - config.put(ExitVMOnException, false); + config.putIfAbsent(ExitVMOnException, false); // ...but we want to see exceptions. - config.put(PrintBailout, true); - config.put(PrintStackTraceOnException, true); + config.putIfAbsent(PrintBailout, true); + config.putIfAbsent(PrintStackTraceOnException, true); } /** @@ -230,12 +228,23 @@ * Compiles all methods in all classes in the Zip/Jar files passed. * * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile - * @throws Throwable + * @throws IOException */ - private void compile(String fileList) throws Throwable { + private void compile(String fileList) throws IOException { final String[] entries = fileList.split(File.pathSeparator); + long start = System.currentTimeMillis(); - try (AutoCloseable s = config.apply()) { + if (Options.CompileTheWorldMultiThreaded.getValue()) { + CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() { + public GraalDebugConfig getDebugConfig() { + return DebugEnvironment.initialize(System.out); + } + }); + int availableProcessors = Runtime.getRuntime().availableProcessors(); + threadPool = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); + } + + try (OverrideScope s = config.apply()) { for (int i = 0; i < entries.length; i++) { final String entry = entries[i]; @@ -312,8 +321,22 @@ } } + if (threadPool != null) { + while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) { + System.out.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles"); + try { + threadPool.awaitTermination(15, TimeUnit.SECONDS); + } catch (InterruptedException e) { + } + } + threadPool = null; + } + + long elapsedTime = System.currentTimeMillis() - start; + println(); - println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter, compileTime, memoryUsed); + println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime, + compileTime.get(), memoryUsed.get()); } class CTWCompilationTask extends CompilationTask { @@ -332,10 +355,24 @@ } } + private void compileMethod(HotSpotResolvedJavaMethod method) { + if (threadPool != null) { + threadPool.submit(new Runnable() { + public void run() { + try (OverrideScope s = config.apply()) { + compileMethod(method, classFileCounter); + } + } + }); + } else { + compileMethod(method, classFileCounter); + } + } + /** * Compiles a method and gathers some statistics. */ - private void compileMethod(HotSpotResolvedJavaMethod method) { + private void compileMethod(HotSpotResolvedJavaMethod method, int counter) { try { long start = System.currentTimeMillis(); long allocatedAtStart = getCurrentThreadAllocatedBytes(); @@ -344,12 +381,12 @@ CompilationTask task = new CTWCompilationTask(backend, method); task.runCompilation(); - memoryUsed += getCurrentThreadAllocatedBytes() - allocatedAtStart; - compileTime += (System.currentTimeMillis() - start); - compiledMethodsCounter++; + memoryUsed.getAndAdd(getCurrentThreadAllocatedBytes() - allocatedAtStart); + compileTime.getAndAdd(System.currentTimeMillis() - start); + compiledMethodsCounter.incrementAndGet(); } catch (Throwable t) { // Catch everything and print a message - println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, method.format("%H.%n(%p):%r")); + println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r")); t.printStackTrace(TTY.cachedOut); } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Mon Mar 23 16:11:48 2015 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.hotspot.word.*; import com.oracle.graal.nodes.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; @@ -48,6 +49,11 @@ } @Override + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { + return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method); + } + + @Override protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Executable originalMethod, Method substituteMethod) { final Class substituteClass = substituteMethod.getDeclaringClass(); if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,17 +33,14 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** * HotSpot implementation of {@link ConstantReflectionProvider}. */ -@SuppressWarnings("unused") public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { private static final String SystemClassName = "Ljava/lang/System;"; @@ -317,7 +314,7 @@ ResolvedJavaMethod initMethod = null; try { Class rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class)); initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Mar 23 16:11:48 2015 +0100 @@ -22,16 +22,17 @@ */ package com.oracle.graal.hotspot.meta; -import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; @@ -68,7 +69,7 @@ plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes)); plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection)); plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); - plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, replacements)); + plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin)); registerObjectPlugins(invocationPlugins); @@ -83,14 +84,15 @@ private static void registerObjectPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Object.class); r.register1("getClass", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode rcvr = receiver.get(); ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); ValueNode mirror; - if (objectStamp.isExactType() && objectStamp.nonNull()) { + if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) { mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess())); } else { StampProvider stampProvider = b.getStampProvider(); - LoadHubNode hub = b.append(new LoadHubNode(stampProvider, nullCheckedValue(b, rcvr))); + LoadHubNode hub = b.append(new LoadHubNode(stampProvider, rcvr)); mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub)); } b.push(Kind.Object, mirror); @@ -102,7 +104,7 @@ private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) { Registration r = new Registration(plugins, System.class); r.register0("currentTimeMillis", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long)); b.push(Kind.Long, b.append(foreignCall)); foreignCall.setStateAfter(b.createStateAfter()); @@ -110,7 +112,7 @@ } }); r.register0("nanoTime", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long)); b.push(Kind.Long, b.append(foreignCall)); foreignCall.setStateAfter(b.createStateAfter()); @@ -122,7 +124,7 @@ private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) { Registration r = new Registration(plugins, Thread.class); r.register0("currentThread", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind())); ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset)); boolean compressible = false; @@ -138,9 +140,9 @@ private static void registerStableOptionPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, StableOptionValue.class); r.register1("getValue", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) { - if (rcvr.isConstant() && !rcvr.isNullConstant()) { - Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object(); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + if (receiver.isConstant()) { + Object object = ((HotSpotObjectConstantImpl) receiver.get().asConstant()).object(); StableOptionValue option = (StableOptionValue) object; ConstantNode value = b.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess())); b.push(Kind.Object, value); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.meta; - -import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; -import static java.lang.String.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; -import com.oracle.graal.hotspot.word.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.word.*; - -public final class HotSpotInlineInvokePlugin implements InlineInvokePlugin { - private final ReplacementsImpl replacements; - private final NodeIntrinsificationPhase nodeIntrinsification; - - public HotSpotInlineInvokePlugin(NodeIntrinsificationPhase nodeIntrinsification, ReplacementsImpl replacements) { - this.nodeIntrinsification = nodeIntrinsification; - this.replacements = replacements; - } - - public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { - ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method); - if (subst != null) { - if (b.parsingReplacement() || InlineDuringParsing.getValue()) { - // Forced inlining of intrinsics - return new InlineInfo(subst, true, true); - } - } - if (b.parsingReplacement()) { - assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null && - !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); - - // Force inlining when parsing replacements - return new InlineInfo(method, true, true); - } else { - assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), - method.format("%h.%n"), b); - if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { - return new InlineInfo(method, false, false); - } - } - return null; - } - - public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { - if (b.parsingReplacement()) { - boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null; - Replacement replacement = b.getReplacement(); - assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"), - method.format("%h.%n(%p)")); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Mon Mar 23 16:11:48 2015 +0100 @@ -23,8 +23,13 @@ package com.oracle.graal.hotspot.meta; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin; /** @@ -65,6 +70,22 @@ return; } } + super.register(plugin, declaringClass, name, argumentTypes); } + + @Override + public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { + if (GraalOptions.ImmutableCode.getValue()) { + for (Node node : newNodes) { + if (node instanceof ConstantNode) { + ConstantNode c = (ConstantNode) node; + if (c.getKind() == Kind.Object && !AheadOfTimeVerificationPhase.isLegalObjectConstant(c)) { + throw new AssertionError("illegal constant node in AOT: " + node); + } + } + } + } + super.checkNewNodes(b, plugin, newNodes); + } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Mon Mar 23 16:11:48 2015 +0100 @@ -526,7 +526,7 @@ Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes()); toJavaCache = result; return result; - } catch (NoSuchMethodException e) { + } catch (NoSuchMethodException | NoClassDefFoundError e) { return null; } } @@ -539,7 +539,7 @@ Constructor result = holder.mirror().getDeclaredConstructor(signatureToTypes()); toJavaCache = result; return result; - } catch (NoSuchMethodException e) { + } catch (NoSuchMethodException | NoClassDefFoundError e) { return null; } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java Mon Mar 23 16:11:48 2015 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.spi.*; import com.oracle.graal.hotspot.meta.*; @@ -53,7 +54,7 @@ @Override public Node canonical(CanonicalizerTool tool) { ValueNode javaClass = getJavaClass(); - if (javaClass.isConstant()) { + if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) { HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant(); JavaConstant classLoader = c.getClassLoader(); if (classLoader != null) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Mon Mar 23 16:11:48 2015 +0100 @@ -32,9 +32,8 @@ import com.oracle.graal.phases.tiers.*; /** - * Checks for illegal object constants in a graph processed for AOT compilation. The only legal - * object constants are {@linkplain String#intern() interned} strings as they will be installed in - * the Class Data Sharing (CDS) space. + * Checks for {@link #isLegalObjectConstant(ConstantNode) illegal} object constants in a graph + * processed for AOT compilation. * * @see LoadJavaMirrorWithKlassPhase */ @@ -43,13 +42,17 @@ @Override protected boolean verify(StructuredGraph graph, PhaseContext context) { for (ConstantNode node : getConstantNodes(graph)) { - if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) { + if (isLegalObjectConstant(node)) { throw new VerificationError("illegal object constant: " + node); } } return true; } + public static boolean isLegalObjectConstant(ConstantNode node) { + return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node); + } + private static boolean isObject(ConstantNode node) { return node.getKind() == Kind.Object; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Mon Mar 23 16:11:48 2015 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.nodes.spi.Replacements.*; - import java.lang.reflect.*; import java.util.zip.*; @@ -64,9 +62,7 @@ replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); - if (SELF_RECURSIVE_INTRINSICS_ENABLED) { - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); - replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); - } + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class); + replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class); } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Mon Mar 23 16:11:48 2015 +0100 @@ -192,7 +192,7 @@ StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO); graph.disableInlinedMethodRecording(); - GraphKit kit = new GraphKit(graph, providers, wordTypes); + GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); ParameterNode[] params = createParameters(kit, args); ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java Mon Mar 23 16:11:48 2015 +0100 @@ -29,9 +29,10 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; @@ -94,7 +95,8 @@ assert SnippetGraphUnderConstruction.get() == null; SnippetGraphUnderConstruction.set(graph); - new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph); + ReplacementContext initialReplacementContext = new ReplacementContext(method, method); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); SnippetGraphUnderConstruction.set(null); graph.setGuardsStage(GuardsStage.FLOATING_GUARDS); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Mon Mar 23 16:11:48 2015 +0100 @@ -27,6 +27,7 @@ import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.HIRFrameStateBuilder.*; import java.util.*; @@ -38,10 +39,12 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.debug.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -81,7 +84,7 @@ * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation * is a {@link MethodSubstitution} or a snippet. */ - static class ReplacementContext implements Replacement { + public static class ReplacementContext implements Replacement { /** * The method being replaced. */ @@ -120,6 +123,11 @@ IntrinsicContext asIntrinsic() { return null; } + + @Override + public String toString() { + return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}"; + } } /** @@ -128,25 +136,37 @@ * information required to build a frame state denoting the JVM state just before the * intrinsified call. */ - static class IntrinsicContext extends ReplacementContext { + public static class IntrinsicContext extends ReplacementContext { /** - * The arguments to the intrinsified invocation. + * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed. */ - private final ValueNode[] invokeArgs; + public static final int POST_PARSE_INLINE_BCI = -1; + + /** + * BCI denoting an intrinsic is the compilation root. + */ + public static final int ROOT_COMPILATION_BCI = -2; /** - * The BCI of the intrinsified invocation. + * The arguments to the intrinsic. */ - private final int invokeBci; + ValueNode[] args; - private FrameState invokeStateBefore; - private FrameState invokeStateDuring; + /** + * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or + * {@link #ROOT_COMPILATION_BCI}. + */ + final int bci; - public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] invokeArgs, int invokeBci) { + private FrameState stateBeforeCache; + + public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) { super(method, substitute); - this.invokeArgs = invokeArgs; - this.invokeBci = invokeBci; + assert bci != POST_PARSE_INLINE_BCI || args == null; + this.args = args; + this.bci = bci; + assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)"); } @Override @@ -154,34 +174,56 @@ return true; } - /** - * Gets the frame state that will restart the interpreter just before the intrinsified - * invocation. - */ - public FrameState getInvokeStateBefore(BytecodeParser parent) { - assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; - if (invokeStateDuring == null) { - assert invokeStateBefore == null; - // Find the ancestor calling the replaced method - BytecodeParser ancestor = parent; - while (ancestor.parsingReplacement()) { - ancestor = ancestor.getParent(); - } - invokeStateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); - invokeStateBefore = invokeStateDuring.duplicateModifiedBeforeCall(invokeBci, Kind.Void, invokeArgs); - } - return invokeStateBefore; + public boolean isPostParseInlined() { + return bci == POST_PARSE_INLINE_BCI; + } + + public boolean isCompilationRoot() { + return bci == ROOT_COMPILATION_BCI; } - public FrameState getInvokeStateDuring() { - assert invokeStateDuring != null : "must only be called after getInvokeStateBefore()"; - return invokeStateDuring; + public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) { + if (isCompilationRoot()) { + int maxLocals = method.getMaxLocals(); + // The 'args' were initialized based on the intrinsic method but a + // frame state's 'locals' needs to have the same length as the frame + // state method's 'max_locals'. + ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals); + ValueNode[] stack = EMPTY_ARRAY; + int stackSize = 0; + ValueNode[] locks = EMPTY_ARRAY; + List monitorIds = Collections.emptyList(); + return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false)); + } else if (isPostParseInlined()) { + return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); + } else { + assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext; + if (stateBeforeCache == null) { + assert stateBeforeCache == null; + + // Find the non-intrinsic ancestor calling the intrinsified method + BytecodeParser ancestor = parent; + while (ancestor.parsingReplacement()) { + assert ancestor.replacementContext instanceof IntrinsicContext; + ancestor = ancestor.getParent(); + } + FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true); + stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args); + } + return stateBeforeCache; + } } @Override IntrinsicContext asIntrinsic() { return this; } + + @Override + public String toString() { + return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci + + (args == null ? "" : ", args: " + Arrays.toString(args)) + (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}"; + } } /** @@ -333,11 +375,8 @@ protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind); private void genLoadIndexed(Kind kind) { - - emitExplicitExceptions(frameState.peek(1), frameState.peek(0)); - ValueNode index = frameState.ipop(); - ValueNode array = frameState.apop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); if (!tryLoadIndexedPlugin(kind, index, array)) { frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); } @@ -360,11 +399,9 @@ protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); private void genStoreIndexed(Kind kind) { - emitExplicitExceptions(frameState.peek(2), frameState.peek(1)); - ValueNode value = frameState.pop(kind.getStackKind()); ValueNode index = frameState.ipop(); - ValueNode array = frameState.apop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); genStoreIndexed(array, index, kind, value); } @@ -832,10 +869,8 @@ protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field); private void genGetField(JavaField field) { - emitExplicitExceptions(frameState.peek(0), null); - Kind kind = field.getKind(); - ValueNode receiver = frameState.apop(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { @@ -846,36 +881,53 @@ } } - protected abstract void emitNullCheck(ValueNode receiver); + /** + * Emits control flow to null check a receiver if it's stamp does not indicate it is + * {@linkplain StampTool#isPointerNonNull always non-null}. + * + * @return the receiver with a stamp indicating non-nullness + */ + protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver); - protected abstract void emitBoundsCheck(ValueNode index, ValueNode length); + /** + * Emits control flow to check an array index is within bounds of an array's length. + * + * @param index the index to check + * @param length the length of the array being indexed + */ + protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length); private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); protected abstract ValueNode genArrayLength(ValueNode x); - protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { + /** + * @param receiver the receiver of an object based operation + * @param index the index of an array based operation that is to be tested for out of bounds. + * This is null for a non-array operation. + * @return the receiver value possibly modified to have a tighter stamp + */ + protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { assert receiver != null; if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null || (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { - return; + return receiver; } - emitNullCheck(receiver); - if (outOfBoundsIndex != null) { - ValueNode length = append(genArrayLength(receiver)); - emitBoundsCheck(outOfBoundsIndex, length); + ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); + if (index != null) { + ValueNode length = append(genArrayLength(nonNullReceiver)); + emitExplicitBoundsCheck(index, length); } EXPLICIT_EXCEPTIONS.increment(); + return nonNullReceiver; } protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); private void genPutField(JavaField field) { - emitExplicitExceptions(frameState.peek(1), null); - ValueNode value = frameState.pop(field.getKind().getStackKind()); - ValueNode receiver = frameState.apop(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { genStoreField(receiver, (ResolvedJavaField) field, value); } else { @@ -1033,7 +1085,7 @@ protected abstract ValueNode appendConstant(JavaConstant constant); - protected abstract ValueNode append(ValueNode v); + protected abstract T append(T v); protected boolean isNeverExecutedCode(double probability) { return probability == 0 && optimisticOpts.removeNeverExecutedCode(); @@ -1093,214 +1145,214 @@ // Checkstyle: stop // @formatter:off - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; - case ICONST_M1 : // fall through - case ICONST_0 : // fall through - case ICONST_1 : // fall through - case ICONST_2 : // fall through - case ICONST_3 : // fall through - case ICONST_4 : // fall through - case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; - case LCONST_0 : // fall through - case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; - case FCONST_0 : // fall through - case FCONST_1 : // fall through - case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; - case DCONST_0 : // fall through - case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; - case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; - case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; - case IALOAD : genLoadIndexed(Kind.Int ); break; - case LALOAD : genLoadIndexed(Kind.Long ); break; - case FALOAD : genLoadIndexed(Kind.Float ); break; - case DALOAD : genLoadIndexed(Kind.Double); break; - case AALOAD : genLoadIndexed(Kind.Object); break; - case BALOAD : genLoadIndexed(Kind.Byte ); break; - case CALOAD : genLoadIndexed(Kind.Char ); break; - case SALOAD : genLoadIndexed(Kind.Short ); break; - case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(Kind.Int ); break; - case LASTORE : genStoreIndexed(Kind.Long ); break; - case FASTORE : genStoreIndexed(Kind.Float ); break; - case DASTORE : genStoreIndexed(Kind.Double); break; - case AASTORE : genStoreIndexed(Kind.Object); break; - case BASTORE : genStoreIndexed(Kind.Byte ); break; - case CASTORE : genStoreIndexed(Kind.Char ); break; - case SASTORE : genStoreIndexed(Kind.Short ); break; - case POP : frameState.xpop(); break; - case POP2 : frameState.xpop(); frameState.xpop(); break; - case DUP : frameState.xpush(frameState.xpeek()); break; - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(Kind.Int, opcode); break; - case IDIV : // fall through - case IREM : genIntegerDivOp(Kind.Int, opcode); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(Kind.Long, opcode); break; - case LDIV : // fall through - case LREM : genIntegerDivOp(Kind.Long, opcode); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(Kind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(Kind.Double, opcode); break; - case INEG : genNegateOp(Kind.Int); break; - case LNEG : genNegateOp(Kind.Long); break; - case FNEG : genNegateOp(Kind.Float); break; - case DNEG : genNegateOp(Kind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(Kind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(Kind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(Kind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(Kind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; - case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; - case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; - case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; - case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; - case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; - case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; - case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; - case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; - case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; - case L2I : genNarrow(Kind.Long, Kind.Int); break; - case I2L : genSignExtend(Kind.Int, Kind.Long); break; - case I2B : genSignExtend(Kind.Byte, Kind.Int); break; - case I2S : genSignExtend(Kind.Short, Kind.Int); break; - case I2C : genZeroExtend(Kind.Char, Kind.Int); break; - case LCMP : genCompareOp(Kind.Long, false); break; - case FCMPL : genCompareOp(Kind.Float, true); break; - case FCMPG : genCompareOp(Kind.Float, false); break; - case DCMPL : genCompareOp(Kind.Double, true); break; - case DCMPG : genCompareOp(Kind.Double, false); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; - case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; - case GOTO : genGoto(); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; - case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; - case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; - case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; - case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; - case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; - case ARETURN : genReturn(frameState.apop(), Kind.Object); break; - case RETURN : genReturn(null, Kind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(); break; - case JSR_W : genJsr(stream.readBranchDest()); break; - case BREAKPOINT: - throw new BailoutException("concurrent setting of breakpoint"); - default: - throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); - } - // @formatter:on + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : frameState.xpop(); break; + case POP2 : frameState.xpop(); frameState.xpop(); break; + case DUP : frameState.xpush(frameState.xpeek()); break; + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; + case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; + case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; + case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; + case ARETURN : genReturn(frameState.apop(), Kind.Object); break; + case RETURN : genReturn(null, Kind.Void); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on // Checkstyle: resume } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Mon Mar 23 16:11:48 2015 +0100 @@ -51,6 +51,15 @@ * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract) */ public String disassemble(ResolvedJavaMethod method) { + return disassemble(method, 0, Integer.MAX_VALUE); + } + + /** + * Disassembles the bytecode of a given method in a {@code javap}-like format. + * + * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract) + */ + public String disassemble(ResolvedJavaMethod method, int startBci, int endBci) { if (method.getCode() == null) { return null; } @@ -60,10 +69,11 @@ int opcode = stream.currentBC(); while (opcode != Bytecodes.END) { int bci = stream.currentBCI(); - String mnemonic = Bytecodes.nameOf(opcode); - buf.append(String.format("%4d: %-14s", bci, mnemonic)); - if (stream.nextBCI() > bci + 1) { - // @formatter:off + if (bci >= startBci && bci <= endBci) { + String mnemonic = Bytecodes.nameOf(opcode); + buf.append(String.format("%4d: %-14s", bci, mnemonic)); + if (stream.nextBCI() > bci + 1) { + // @formatter:off switch (opcode) { case BIPUSH : buf.append(stream.readByte()); break; case SIPUSH : buf.append(stream.readShort()); break; @@ -211,8 +221,9 @@ } } // @formatter:on + } + buf.append(String.format("%n")); } - buf.append(String.format("%n")); stream.next(); opcode = stream.currentBC(); } diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Mar 23 16:11:48 2015 +0100 @@ -25,10 +25,12 @@ import static com.oracle.graal.api.meta.DeoptimizationAction.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; +import static com.oracle.graal.compiler.common.GraalInternalError.*; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.graph.iterators.NodePredicates.*; +import static com.oracle.graal.compiler.common.type.StampFactory.*; import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; import static com.oracle.graal.nodes.StructuredGraph.*; +import static com.oracle.graal.nodes.type.StampTool.*; import static java.lang.String.*; import java.util.*; @@ -48,6 +50,7 @@ import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; @@ -97,7 +100,9 @@ * Furthermore, if it is non-null and not equal to {@link #rootMethod} then this is the * original method for which a snippet exists (e.g., System.arraycopy()). */ - private final ResolvedJavaMethod rootMethodIsReplacement; + // private final ResolvedJavaMethod rootMethodIsReplacement; + + private final ReplacementContext initialReplacementContext; private final GraphBuilderConfiguration graphBuilderConfig; private final OptimisticOptimizations optimisticOpts; @@ -106,20 +111,21 @@ private final SnippetReflectionProvider snippetReflectionProvider; public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; this.stampProvider = stampProvider; this.constantReflection = constantReflection; this.snippetReflectionProvider = snippetReflectionProvider; - this.rootMethodIsReplacement = rootMethodIsReplacement; + this.initialReplacementContext = initialReplacementContext; + assert metaAccess != null; } public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) { - this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) { + this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } @Override @@ -131,10 +137,10 @@ this.currentGraph = graph; TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { - ReplacementContext replacementContext = rootMethodIsReplacement != null ? new ReplacementContext(rootMethodIsReplacement, rootMethod) : null; + ReplacementContext replacementContext = initialReplacementContext; BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext); HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); - frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || rootMethodIsReplacement != null, graphBuilderConfig.getPlugins().getParameterPlugin()); + frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); parser.build(graph.start(), frameState); parser.connectLoopEndToBegin(); @@ -232,6 +238,42 @@ } } + static class InvocationPluginReceiver implements Receiver { + final BytecodeParser parser; + ValueNode[] args; + ValueNode value; + + public InvocationPluginReceiver(BytecodeParser parser) { + this.parser = parser; + } + + @Override + public ValueNode get() { + assert args != null : "Cannot get the receiver of a static method"; + if (value == null) { + value = parser.nullCheckedValue(args[0]); + if (value != args[0]) { + args[0] = value; + } + } + return value; + } + + @Override + public boolean isConstant() { + return args[0].isConstant(); + } + + InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) { + if (!targetMethod.isStatic()) { + this.args = newArgs; + this.value = null; + return this; + } + return null; + } + } + public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { private BciBlockMapping blockMap; @@ -257,6 +299,7 @@ private Stack explodeLoopsContext; private int nextPeelIteration = 1; private boolean controlFlowSplit; + private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); private FixedWithNextNode[] firstInstructionArray; private HIRFrameStateBuilder[] entryStateArray; @@ -384,6 +427,28 @@ } } + /** + * Gets a version of a given value that has a + * {@linkplain StampTool#isPointerNonNull(ValueNode) non-null} stamp. + */ + ValueNode nullCheckedValue(ValueNode value) { + if (!StampTool.isPointerNonNull(value.stamp())) { + IsNullNode condition = currentGraph.unique(new IsNullNode(value)); + ObjectStamp receiverStamp = (ObjectStamp) value.stamp(); + Stamp stamp = receiverStamp.join(objectNonNull()); + FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); + PiNode nonNullReceiver = currentGraph.unique(new PiNode(value, stamp)); + nonNullReceiver.setGuard(fixedGuard); + // TODO: Propogating the non-null into the frame state would + // remove subsequent null-checks on the same value. However, + // it currently causes an assertion failure when merging states. + // + // frameState.replace(value, nonNullReceiver); + return nonNullReceiver; + } + return value; + } + private void detectLoops(FixedNode startInstruction) { NodeBitMap visited = currentGraph.createNodeBitMap(); NodeBitMap active = currentGraph.createNodeBitMap(); @@ -946,21 +1011,24 @@ } @Override - protected void emitNullCheck(ValueNode receiver) { + protected ValueNode emitExplicitNullCheck(ValueNode receiver) { if (StampTool.isPointerNonNull(receiver.stamp())) { - return; + return receiver; } BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class)); AbstractBeginNode falseSucc = currentGraph.add(new BeginNode()); + PiNode nonNullReceiver = currentGraph.unique(new PiNode(receiver, receiver.stamp().join(objectNonNull()))); + nonNullReceiver.setGuard(falseSucc); append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01)); lastInstr = falseSucc; exception.setStateAfter(createFrameState(bci())); exception.setNext(handleException(exception, bci())); + return nonNullReceiver; } @Override - protected void emitBoundsCheck(ValueNode index, ValueNode length) { + protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = currentGraph.add(new BeginNode()); BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); append(new IfNode(currentGraph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); @@ -1101,11 +1169,16 @@ returnType = returnType.resolve(targetMethod.getDeclaringClass()); } if (invokeKind.hasReceiver()) { - emitExplicitExceptions(args[0], null); + args[0] = emitExplicitExceptions(args[0], null); if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) { JavaTypeProfile profile = profilingInfo.getTypeProfile(bci()); args[0] = TypeProfileProxyNode.proxify(args[0], profile); } + + if (args[0].isNullConstant()) { + append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); + return; + } } if (tryGenericInvocationPlugin(args, targetMethod)) { @@ -1149,22 +1222,70 @@ } } + /** + * Contains all the assertion checking logic around the application of an + * {@link InvocationPlugin}. This class is only loaded when assertions are enabled. + */ + class InvocationPluginAssertions { + final InvocationPlugin plugin; + final ValueNode[] args; + final ResolvedJavaMethod targetMethod; + final Kind resultType; + final int beforeStackSize; + final boolean needsNullCheck; + final int nodeCount; + final Mark mark; + + public InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) { + guarantee(assertionsEnabled(), "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName()); + this.plugin = plugin; + this.targetMethod = targetMethod; + this.args = args; + this.resultType = resultType; + this.beforeStackSize = frameState.stackSize; + this.needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp()); + this.nodeCount = currentGraph.getNodeCount(); + this.mark = currentGraph.getMark(); + } + + String error(String format, Object... a) { + return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess)); + } + + boolean check(boolean pluginResult) { + if (pluginResult == true) { + assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : error("plugin manipulated the stack incorrectly"); + NodeIterable newNodes = currentGraph.getNewNodes(mark); + assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]); + for (Node n : newNodes) { + if (n instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) n; + assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(), + targetMethod.format("%H.%n(%p)"), stateSplit); + } + } + try { + graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes); + } catch (Throwable t) { + throw new AssertionError(error("Error in plugin"), t); + } + } else { + assert nodeCount == currentGraph.getNodeCount() : error("plugin that returns false must not create new nodes"); + assert beforeStackSize == frameState.stackSize : error("plugin that returns false must modify the stack"); + } + return true; + } + } + private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) { InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); if (plugin != null) { - int beforeStackSize = frameState.stackSize; - boolean needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp()); - int nodeCount = currentGraph.getNodeCount(); - Mark mark = needsNullCheck ? currentGraph.getMark() : null; - if (InvocationPlugin.execute(this, targetMethod, plugin, args)) { - assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly " + targetMethod; - assert !needsNullCheck || args[0].usages().filter(isNotA(FrameState.class)).isEmpty() || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : format( - "plugin needs to null check the receiver of %s: receiver=%s%n\tplugin at %s", targetMethod.format("%H.%n(%p)"), args[0], - plugin.getApplySourceLocation(metaAccess)); + InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; + if (InvocationPlugin.execute(this, targetMethod, plugin, invocationPluginReceiver.init(targetMethod, args), args)) { + assert assertions.check(true); return true; } - assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes"; - assert beforeStackSize == frameState.stackSize : "plugin that returns false must modify the stack"; + assert assertions.check(false); } return false; } @@ -1174,18 +1295,6 @@ return plugin != null && plugin.apply(this, targetMethod, args); } - private boolean containsNullCheckOf(NodeIterable nodes, Node value) { - for (Node n : nodes) { - if (n instanceof GuardingPiNode) { - GuardingPiNode pi = (GuardingPiNode) n; - if (pi.condition() instanceof IsNullNode) { - return ((IsNullNode) pi.condition()).getValue() == value; - } - } - } - return false; - } - private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaType returnType) { InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin(); if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) { @@ -1210,13 +1319,30 @@ } ReplacementContext context = this.replacementContext; if (context != null && context.isCallToOriginal(targetMethod)) { - assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying"; - // Self recursive replacement means the original - // method should be called. - if (context.method.hasBytecodes()) { - parseAndInlineCallee(context.method, args, null); + IntrinsicContext intrinsic = context.asIntrinsic(); + if (intrinsic != null) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + deopt.setStateBefore(intrinsic.getInvokeStateBefore(currentGraph, null)); + return true; + } else { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see HIRFrameStateBuilder.create(int bci)). + parseAndInlineCallee(context.method, args, null); + return true; + } } else { - return false; + // Self recursive replacement means the original + // method should be called. + if (context.method.hasBytecodes()) { + parseAndInlineCallee(context.method, args, null); + return true; + } else { + return false; + } } } else { if (context == null && inlineInfo.isReplacement) { @@ -1275,6 +1401,9 @@ private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) { BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext); HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, currentGraph); + if (!targetMethod.isStatic()) { + args[0] = nullCheckedValue(args[0]); + } startFrameState.initializeFromArgumentsArray(args); parser.build(this.lastInstr, startFrameState); @@ -1444,61 +1573,41 @@ return ConstantNode.forConstant(constant, metaAccess, currentGraph); } - @SuppressWarnings("unchecked") @Override - public ValueNode append(ValueNode v) { + public T append(T v) { if (v.graph() != null) { - // This node was already appended to the graph. return v; } - if (v instanceof ControlSinkNode) { - return append((ControlSinkNode) v); - } - if (v instanceof ControlSplitNode) { - return append((ControlSplitNode) v); - } - if (v instanceof FixedWithNextNode) { - return append((FixedWithNextNode) v); + T added = currentGraph.addOrUnique(v); + if (added == v) { + updateLastInstruction(v); } - if (v instanceof FloatingNode) { - return append((FloatingNode) v); - } - throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName()); - } - - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = null; return added; } - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = null; + public T recursiveAppend(T v) { + if (v.graph() != null) { + return v; + } + T added = currentGraph.addOrUniqueWithInputs(v); + if (added == v) { + updateLastInstruction(v); + } return added; } - public T append(T fixed) { - assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - T added = currentGraph.add(fixed); - lastInstr.setNext(added); - lastInstr = added; - return added; - } - - public T append(T v) { - if (v.graph() != null) { - return v; + private void updateLastInstruction(T v) { + if (v instanceof FixedNode) { + FixedNode fixedNode = (FixedNode) v; + lastInstr.setNext(fixedNode); + if (fixedNode instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; + assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; + lastInstr = fixedWithNextNode; + } else { + lastInstr = null; + } } - T added = currentGraph.unique(v); - return added; } private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { @@ -2362,7 +2471,8 @@ if (bp != this) { fmt.format("%n%s", indent); } - fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bci(), bp.parsingReplacement()); + fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement()); + fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10)); bp = bp.parent; indent += " "; } @@ -2392,4 +2502,11 @@ static String nSpaces(int n) { return n == 0 ? "" : format("%" + n + "s", ""); } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Mon Mar 23 16:11:48 2015 +0100 @@ -43,8 +43,8 @@ public final class HIRFrameStateBuilder { - private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; protected final BytecodeParser parser; protected final ResolvedJavaMethod method; @@ -145,6 +145,14 @@ javaIndex += kind.getSlotCount(); index++; } + + if (parser.replacementContext instanceof IntrinsicContext) { + IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext; + if (intrinsic.isCompilationRoot()) { + // Records the parameters to an root compiled intrinsic + intrinsic.args = locals.clone(); + } + } } private HIRFrameStateBuilder(HIRFrameStateBuilder other) { @@ -200,28 +208,20 @@ if (parser.parsingReplacement()) { IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); if (intrinsic != null) { - assert parent != null : "intrinsics can only be processed in context of a caller"; - - // We're somewhere in an intrinsic. In this case, we want a frame state - // that will restart the interpreter just before the intrinsified - // invocation. - return intrinsic.getInvokeStateBefore(parent); + return intrinsic.getInvokeStateBefore(parser.getGraph(), parent); } } + // If this is the recursive call in a partial intrinsification + // the frame(s) of the intrinsic method are omitted + while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) { + parent = parent.getParent(); + } return create(bci, parent, false); } public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { if (outerFrameState == null && parent != null) { outerFrameState = parent.getFrameState().create(parent.bci()); - if (parser.parsingReplacement()) { - IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic(); - if (intrinsic != null) { - // A side-effect of creating the frame state in a replacing - // parent is that the 'during' frame state is created as well - outerFrameState = intrinsic.getInvokeStateDuring(); - } - } } if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); @@ -297,7 +297,7 @@ ((PhiNode) currentValue).addInput(otherValue); return currentValue; } else if (currentValue != otherValue) { - assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for changed locals and all stack slots"; + assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { return null; } @@ -958,4 +958,17 @@ } return false; } + + public void replace(ValueNode oldValue, ValueNode newValue) { + for (int i = 0; i < locals.length; i++) { + if (locals[i] == oldValue) { + locals[i] = newValue; + } + } + for (int i = 0; i < stackSize; i++) { + if (stack[i] == oldValue) { + stack[i] = newValue; + } + } + } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java Mon Mar 23 16:11:48 2015 +0100 @@ -35,7 +35,7 @@ } public static double test(double arg) throws NaN { - double v = Math.sin(arg); + double v = Math.sin(arg) * Math.sin(arg * 5); if (Double.isNaN(v)) { // NaN can't be tested against itself throw new NaN(); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Binary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Binary.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.CompilationResult.DataSectionReference; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +/** + * AMD64 LIR instructions that have two inputs and one output. + */ +public class AMD64Binary { + + /** + * Instruction that has two {@link AllocatableValue} operands. + */ + public static class Op extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Op.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG, STACK}) protected AllocatableValue y; + + public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(result), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Commutative instruction that has two {@link AllocatableValue} operands. + */ + public static class CommutativeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CommutativeOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public CommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AllocatableValue input; + if (sameRegister(result, y)) { + input = x; + } else { + AMD64Move.move(crb, masm, result, x); + input = y; + } + + if (isRegister(input)) { + opcode.emit(masm, size, asRegister(result), asRegister(input)); + } else { + assert isStackSlot(input); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. + */ + public static class ConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + private final int y; + + public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y); + } + + public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result), y); + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one + * {@link DataSectionReference} operand. + */ + public static class DataOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DataOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + private final JavaConstant y; + + private final int alignment; + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { + this(opcode, size, result, x, y, y.getKind().getByteCount()); + } + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue + * memory} operand. + */ + public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), y.toAddress()); + } + + @Override + public void verify() { + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit + * immediate input. + */ + public static class RMIOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RMIOp.class); + + @Opcode private final AMD64RMIOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + private final int y; + + public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(result), asRegister(x), y); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y); + } + } + } +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64BinaryCommutativeOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryCommutativeOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Use({REG, STACK}) protected AllocatableValue y; - - public AMD64BinaryCommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AllocatableValue input; - if (sameRegister(result, y)) { - input = x; - } else { - AMD64Move.move(crb, masm, result, x); - input = y; - } - - if (isRegister(input)) { - opcode.emit(masm, size, asRegister(result), asRegister(input)); - } else { - assert isStackSlot(input); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64BinaryConstOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryConstOp.class); - - @Opcode private final AMD64MIOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public AMD64BinaryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { - this(opcode.getMIOpcode(size, NumUtil.isByte(y.asLong())), size, result, x, y); - } - - public AMD64BinaryConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - assert NumUtil.is32bit(y.asLong()); - opcode.emit(masm, size, asRegister(result), (int) y.asLong()); - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConsumer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConsumer.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.CompilationResult.DataSectionReference; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +/** + * AMD64 LIR instructions that have two input operands, but no output operand. + */ +public class AMD64BinaryConsumer { + + /** + * Instruction that has two {@link AllocatableValue} operands. + */ + public static class Op extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(Op.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(y)) { + opcode.emit(masm, size, asRegister(x), asRegister(y)); + } else { + assert isStackSlot(y); + opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y)); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. + */ + public static class ConstOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({REG, STACK}) protected AllocatableValue x; + private final int y; + + public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y); + } + + public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { + this(TYPE, opcode, size, x, y); + } + + protected ConstOp(LIRInstructionClass c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { + super(c); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(x)) { + opcode.emit(masm, size, asRegister(x), y); + } else { + assert isStackSlot(x); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y); + } + } + } + + /** + * Instruction that has one {@link AllocatableValue} operand and one + * {@link DataSectionReference} operand. + */ + public static class DataOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DataOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + private final Constant y; + + private final int alignment; + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) { + this(opcode, size, x, y, size.getBytes()); + } + + public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.alignment = alignment; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); + } + } + + /** + * Instruction that has an {@link AllocatableValue} as first input and a + * {@link AMD64AddressValue memory} operand as second input. + */ + public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryRMOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Use({REG}) protected AllocatableValue x; + @Use({COMPOSITE}) protected AMD64AddressValue y; + + @State protected LIRFrameState state; + + public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(x), y.toAddress()); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an + * {@link AllocatableValue} as second input. + */ + public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryMROp.class); + + @Opcode private final AMD64MROp opcode; + private final OperandSize size; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + @Use({REG}) protected AllocatableValue y; + + @State protected LIRFrameState state; + + public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, x.toAddress(), asRegister(y)); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } + + /** + * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate + * operand. + */ + public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryConstOp.class); + + @Opcode private final AMD64MIOp opcode; + private final OperandSize size; + + @Use({COMPOSITE}) protected AMD64AddressValue x; + private final int y; + + @State protected LIRFrameState state; + + public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state); + } + + public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + this(TYPE, opcode, size, x, y, state); + } + + protected MemoryConstOp(LIRInstructionClass c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { + super(c); + this.opcode = opcode; + this.size = size; + + this.x = x; + this.y = y; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, x.toAddress(), y); + } + + @Override + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; -import com.oracle.graal.lir.asm.*; - -public class AMD64BinaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryMemoryOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Alive({COMPOSITE}) protected AMD64AddressValue y; - - @State protected LIRFrameState state; - - public AMD64BinaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - opcode.emit(masm, size, asRegister(result), y.toAddress()); - } - - @Override - public void verify() { - super.verify(); - assert differentRegisters(result, y) || sameRegister(x, y); - } - - @Override - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { - state = nullCheckState; - return true; - } - return false; - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64BinaryOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - @Alive({REG, STACK}) protected AllocatableValue y; - - public AMD64BinaryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - if (isRegister(y)) { - opcode.emit(masm, size, asRegister(result), asRegister(y)); - } else { - assert isStackSlot(y); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.asm.amd64.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64BinaryPatchOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64BinaryPatchOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - private final int alignment; - - public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { - this(opcode, size, result, x, y, y.getKind().getByteCount()); - } - - public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - - this.alignment = alignment; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, x); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64CompareConstOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareConstOp.class); - - @Opcode private final AMD64MIOp opcode; - private final OperandSize size; - - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public AMD64CompareConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert NumUtil.is32bit(y.asLong()); - if (isRegister(x)) { - opcode.emit(masm, size, asRegister(x), (int) y.asLong()); - } else { - assert isStackSlot(x); - opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), (int) y.asLong()); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; -import com.oracle.graal.lir.asm.*; - -public class AMD64CompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareMemoryConstOp.class); - - @Opcode private final AMD64MIOp opcode; - private final OperandSize size; - - @Use({COMPOSITE}) protected AMD64AddressValue x; - protected JavaConstant y; - - @State protected LIRFrameState state; - - public AMD64CompareMemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, JavaConstant y, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.x = x; - this.y = y; - - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - assert NumUtil.is32bit(y.asLong()); - opcode.emit(masm, size, x.toAddress(), (int) y.asLong()); - } - - @Override - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { - state = nullCheckState; - return true; - } - return false; - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; -import com.oracle.graal.lir.asm.*; - -public class AMD64CompareMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareMemoryOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Use({REG}) protected AllocatableValue x; - @Use({COMPOSITE}) protected AMD64AddressValue y; - - @State protected LIRFrameState state; - - public AMD64CompareMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.x = x; - this.y = y; - - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - opcode.emit(masm, size, asRegister(x), y.toAddress()); - } - - @Override - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { - state = nullCheckState; - return true; - } - return false; - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.asm.amd64.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64CompareOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CompareOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Use({REG}) protected AllocatableValue x; - @Use({REG, STACK}) protected AllocatableValue y; - - public AMD64CompareOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(y)) { - opcode.emit(masm, size, asRegister(x), asRegister(y)); - } else { - assert isStackSlot(y); - opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y)); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Mon Mar 23 16:11:48 2015 +0100 @@ -30,11 +30,9 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.lir.StandardOp.NullCheck; import com.oracle.graal.lir.asm.*; @@ -110,210 +108,6 @@ } } - public abstract static class MemOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemOp.class); - - protected final Kind kind; - @Use({COMPOSITE}) protected AMD64AddressValue address; - @State protected LIRFrameState state; - - public MemOp(LIRInstructionClass c, Kind kind, AMD64AddressValue address, LIRFrameState state) { - super(c); - this.kind = kind; - this.address = address; - this.state = state; - } - - protected abstract void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm); - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - emitMemAccess(crb, masm); - } - - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && value.equals(address.base) && address.index.equals(Value.ILLEGAL) && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) { - state = nullCheckState; - return true; - } - return false; - } - } - - public static final class LoadOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadOp.class); - - @Def({REG}) protected AllocatableValue result; - - public LoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { - super(TYPE, kind, address, state); - this.result = result; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - switch (kind) { - case Boolean: - masm.movzbl(asRegister(result), address.toAddress()); - break; - case Byte: - masm.movsbl(asRegister(result), address.toAddress()); - break; - case Char: - masm.movzwl(asRegister(result), address.toAddress()); - break; - case Short: - masm.movswl(asRegister(result), address.toAddress()); - break; - case Int: - masm.movl(asRegister(result), address.toAddress()); - break; - case Long: - masm.movq(asRegister(result), address.toAddress()); - break; - case Float: - masm.movflt(asFloatReg(result), address.toAddress()); - break; - case Double: - masm.movdbl(asDoubleReg(result), address.toAddress()); - break; - case Object: - masm.movq(asRegister(result), address.toAddress()); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - - public static final class ZeroExtendLoadOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ZeroExtendLoadOp.class); - - @Def({REG}) protected AllocatableValue result; - - public ZeroExtendLoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { - super(TYPE, kind, address, state); - this.result = result; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - switch (kind) { - case Boolean: - case Byte: - masm.movzbl(asRegister(result), address.toAddress()); - break; - case Char: - case Short: - masm.movzwl(asRegister(result), address.toAddress()); - break; - case Int: - masm.movl(asRegister(result), address.toAddress()); - break; - case Long: - masm.movq(asRegister(result), address.toAddress()); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - - public static final class StoreOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreOp.class); - - @Use({REG}) protected AllocatableValue input; - - public StoreOp(Kind kind, AMD64AddressValue address, AllocatableValue input, LIRFrameState state) { - super(TYPE, kind, address, state); - this.input = input; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert isRegister(input); - switch (kind) { - case Boolean: - case Byte: - masm.movb(address.toAddress(), asRegister(input)); - break; - case Char: - case Short: - masm.movw(address.toAddress(), asRegister(input)); - break; - case Int: - masm.movl(address.toAddress(), asRegister(input)); - break; - case Long: - masm.movq(address.toAddress(), asRegister(input)); - break; - case Float: - masm.movflt(address.toAddress(), asFloatReg(input)); - break; - case Double: - masm.movsd(address.toAddress(), asDoubleReg(input)); - break; - case Object: - masm.movq(address.toAddress(), asRegister(input)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - - public abstract static class StoreConstantOp extends MemOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StoreConstantOp.class); - - protected final JavaConstant input; - - protected StoreConstantOp(LIRInstructionClass c, Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) { - super(c, kind, address, state); - this.input = input; - } - - @Override - public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - switch (kind) { - case Boolean: - case Byte: - masm.movb(address.toAddress(), input.asInt() & 0xFF); - break; - case Char: - case Short: - masm.movw(address.toAddress(), input.asInt() & 0xFFFF); - break; - case Int: - masm.movl(address.toAddress(), input.asInt()); - break; - case Long: - if (NumUtil.isInt(input.asLong())) { - masm.movslq(address.toAddress(), (int) input.asLong()); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - case Float: - masm.movl(address.toAddress(), floatToRawIntBits(input.asFloat())); - break; - case Double: - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - case Object: - if (input.isNull()) { - masm.movptr(address.toAddress(), 0); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - } - public static final class LeaOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LeaOp.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64MulConstOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MulConstOp.class); - - @Opcode private final AMD64RMIOp opcode; - private final OperandSize size; - - @Def({REG}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public AMD64MulConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert NumUtil.isInt(y.asLong()); - int imm = (int) y.asLong(); - if (isRegister(x)) { - opcode.emit(masm, size, asRegister(result), asRegister(x), imm); - } else { - assert isStackSlot(x); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), imm); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java Mon Mar 23 16:11:48 2015 +0100 @@ -34,6 +34,10 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; +/** + * AMD64 mul/div operation. This operation has a single operand for the second input. The first + * input must be in RAX for mul and in RDX:RAX for div. The result is in RDX:RAX. + */ public class AMD64MulDivOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MulDivOp.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64RegStackConstOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64RegStackConstOp.class); - - @Opcode private final AMD64RMIOp opcode; - private final OperandSize size; - - @Def({REG}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue x; - protected JavaConstant y; - - public AMD64RegStackConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.x = x; - this.y = y; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert NumUtil.is32bit(y.asLong()); - if (isRegister(x)) { - opcode.emit(masm, size, asRegister(result), asRegister(x), (int) y.asLong()); - } else { - assert isStackSlot(x); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), (int) y.asLong()); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,6 +33,10 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; +/** + * AMD64 shift/rotate operation. This operation has a single operand for the first input and output. + * The second input must be in the RCX register. + */ public class AMD64ShiftOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ShiftOp.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Unary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Unary.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.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.asm.amd64.AMD64Assembler.AMD64MOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; +import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; +import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; +import com.oracle.graal.lir.asm.*; + +/** + * AMD64 LIR instructions that have one input and one output. + */ +public class AMD64Unary { + + /** + * Instruction with a single operand that is both input and output. + */ + public static class MOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MOp.class); + + @Opcode private final AMD64MOp opcode; + private final OperandSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public MOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, value); + opcode.emit(masm, size, asRegister(result)); + } + } + + /** + * Instruction with separate input and output operands, and an operand encoding of RM. + */ + public static class RMOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RMOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue value; + + public RMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(value)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(value); + opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value)); + } + } + } + + /** + * Instruction with separate input and output operands, and an operand encoding of MR. + */ + public static class MROp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MROp.class); + + @Opcode private final AMD64MROp opcode; + private final OperandSize size; + + @Def({REG, STACK}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue value; + + public MROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.value = value; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (isRegister(result)) { + opcode.emit(masm, size, asRegister(result), asRegister(value)); + } else { + assert isStackSlot(result); + opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value)); + } + } + } + + /** + * Instruction with a {@link AMD64AddressValue memory} operand. + */ + public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MemoryOp.class); + + @Opcode private final AMD64RMOp opcode; + private final OperandSize size; + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue input; + + @State protected LIRFrameState state; + + public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.input = input; + + this.state = state; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + opcode.emit(masm, size, asRegister(result), input.toAddress()); + } + + public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { + if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { + state = nullCheckState; + return true; + } + return false; + } + } +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64MOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64UnaryMOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMOp.class); - - @Opcode private final AMD64MOp opcode; - private final OperandSize size; - - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue value; - - public AMD64UnaryMOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.value = value; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Move.move(crb, masm, result, value); - opcode.emit(masm, size, asRegister(result)); - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.asm.amd64.AMD64Assembler.AMD64MROp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64UnaryMROp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMROp.class); - - @Opcode private final AMD64MROp opcode; - private final OperandSize size; - - @Def({REG, STACK}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue value; - - public AMD64UnaryMROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.value = value; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(result)) { - opcode.emit(masm, size, asRegister(result), asRegister(value)); - } else { - assert isStackSlot(result); - opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value)); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; -import com.oracle.graal.lir.asm.*; - -public class AMD64UnaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryMemoryOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG}) protected AllocatableValue result; - @Use({COMPOSITE}) protected AMD64AddressValue input; - - @State protected LIRFrameState state; - - public AMD64UnaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.input = input; - - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - opcode.emit(masm, size, asRegister(result), input.toAddress()); - } - - public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { - if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { - state = nullCheckState; - return true; - } - return false; - } -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.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.AMD64Assembler.AMD64RMOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -public class AMD64UnaryRMOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64UnaryRMOp.class); - - @Opcode private final AMD64RMOp opcode; - private final OperandSize size; - - @Def({REG}) protected AllocatableValue result; - @Use({REG, STACK}) protected AllocatableValue value; - - public AMD64UnaryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) { - super(TYPE); - this.opcode = opcode; - this.size = size; - - this.result = result; - this.value = value; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (isRegister(value)) { - opcode.emit(masm, size, asRegister(result), asRegister(value)); - } else { - assert isStackSlot(value); - opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value)); - } - } -} diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Mon Mar 23 16:11:48 2015 +0100 @@ -349,6 +349,11 @@ if (vpn.hasNoUsages()) { continue; } + if (vpn.value() == null) { + assert vpn instanceof GuardProxyNode; + vpn.replaceAtUsages(null); + continue; + } final ValueNode replaceWith; ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value()); if (newVpn != null) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -37,7 +37,7 @@ /** * The {@code ConstantNode} represents a {@link Constant constant}. */ -@NodeInfo(shortName = "Const", nameTemplate = "Const({p#rawvalue})") +@NodeInfo(nameTemplate = "C({p#rawvalue})") public final class ConstantNode extends FloatingNode implements LIRLowerable { public static final NodeClass TYPE = NodeClass.create(ConstantNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -25,7 +25,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; -@NodeInfo(allowedUsageTypes = {InputType.Association}) +@NodeInfo(allowedUsageTypes = {InputType.Association}, nameTemplate = "End") public final class EndNode extends AbstractEndNode { public static final NodeClass TYPE = NodeClass.create(EndNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Mar 23 16:11:48 2015 +0100 @@ -40,7 +40,7 @@ * * This can be used as debug or deoptimization information. */ -@NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}") +@NodeInfo(nameTemplate = "@{p#method/s}:{p#bci}") public final class FrameState extends VirtualState implements IterableNodeType { public static final NodeClass TYPE = NodeClass.create(FrameState.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -28,7 +28,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; -@NodeInfo(allowedUsageTypes = {InputType.Guard}) +@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "Proxy({i#value})") public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(GuardProxyNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -22,10 +22,6 @@ */ package com.oracle.graal.nodes; -import static com.oracle.graal.api.meta.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.compiler.common.type.StampFactory.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; @@ -70,21 +66,6 @@ return action; } - /** - * Returns a node whose stamp is guaranteed to be {@linkplain StampTool#isPointerNonNull(Stamp) - * non-null}. If {@code value} already has such a stamp, then it is returned. Otherwise a fixed - * node guarding {@code value} is returned where the guard performs a null check. - */ - public static ValueNode nullCheckedValue(ValueNode value) { - ObjectStamp receiverStamp = (ObjectStamp) value.stamp(); - if (!StampTool.isPointerNonNull(receiverStamp)) { - IsNullNode condition = value.graph().unique(new IsNullNode(value)); - Stamp stamp = receiverStamp.join(objectNonNull()); - return new GuardingPiNode(value, condition, true, NullCheckException, InvalidateReprofile, stamp); - } - return value; - } - public GuardingPiNode(ValueNode object) { this(object, object.graph().unique(new IsNullNode(object)), true, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, object.stamp().join(StampFactory.objectNonNull())); } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -31,7 +31,7 @@ /** * Memory {@code PhiNode}s merge memory dependencies at control flow merges. */ -@NodeInfo(nameTemplate = "MemoryPhi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) +@NodeInfo(nameTemplate = "Φ({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory}) public final class MemoryPhiNode extends PhiNode implements MemoryNode { public static final NodeClass TYPE = NodeClass.create(MemoryPhiNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -31,7 +31,7 @@ /** * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call. */ -@NodeInfo(nameTemplate = "Param({p#index})") +@NodeInfo(nameTemplate = "P({p#index})") public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider { public static final NodeClass TYPE = NodeClass.create(ParameterNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -30,7 +30,7 @@ /** * The start node of a graph. */ -@NodeInfo(allowedUsageTypes = {InputType.Memory}) +@NodeInfo(allowedUsageTypes = {InputType.Memory}, nameTemplate = "Start") public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint.Single { public static final NodeClass TYPE = NodeClass.create(StartNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -30,7 +30,7 @@ /** * Value {@link PhiNode}s merge data flow values at control flow merges. */ -@NodeInfo(nameTemplate = "ValuePhi({i#values})") +@NodeInfo(nameTemplate = "Φ({i#values})") public class ValuePhiNode extends PhiNode { public static final NodeClass TYPE = NodeClass.create(ValuePhiNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -27,7 +27,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.spi.*; -@NodeInfo +@NodeInfo(nameTemplate = "Proxy({i#value})") public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy { public static final NodeClass TYPE = NodeClass.create(ValueProxyNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -36,7 +36,7 @@ * Location node that is the sum of two other location nodes. Can represent locations in the form of * [(base + x) + y] where base is a node and x and y are location nodes. */ -@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}") +@NodeInfo(nameTemplate = "&+({p#locationIdentity/s})") public final class AddLocationNode extends LocationNode implements Canonicalizable.Binary { public static final NodeClass TYPE = NodeClass.create(AddLocationNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,7 +33,7 @@ * 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}") +@NodeInfo(nameTemplate = "&({p#locationIdentity/s})") public final class ConstantLocationNode extends LocationNode { public static final NodeClass TYPE = NodeClass.create(ConstantLocationNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -37,7 +37,7 @@ * [base + index * scale + disp] where base and index are nodes and scale and disp are integer * constants. */ -@NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}") +@NodeInfo(nameTemplate = "&({p#locationIdentity/s})[{i#index}]") public final class IndexedLocationNode extends LocationNode implements Canonicalizable { public static final NodeClass TYPE = NodeClass.create(IndexedLocationNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; /** * The {@code InstanceOfDynamicNode} represents a type check where the type being checked is not @@ -56,8 +55,6 @@ this.mirror = mirror; this.object = object; assert mirror.getKind() == Kind.Object : mirror.getKind(); - assert StampTool.isExactType(mirror); - assert StampTool.typeOrNull(mirror).getName().equals("Ljava/lang/Class;"); } @Override diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -37,7 +37,7 @@ /** * The {@code LoadFieldNode} represents a read of a static or instance field. */ -@NodeInfo(nameTemplate = "LoadField#{p#field/s}") +@NodeInfo(nameTemplate = "#{p#field/s}") public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary, VirtualizableRoot, UncheckedInterfaceProvider { public static final NodeClass TYPE = NodeClass.create(LoadFieldNode.class); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,8 +33,6 @@ * Interface for managing replacements. */ public interface Replacements { - // Disabled until bug in support for this is fixed. - boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false; /** * Gets the snippet graph derived from a given method. diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Mon Mar 23 16:11:48 2015 +0100 @@ -91,7 +91,7 @@ private static void iterateSuccessorsAndInputs(NodeFlood flood) { BiConsumer consumer = (n, succOrInput) -> { - assert succOrInput.isAlive() : succOrInput; + assert succOrInput.isAlive() : "dead successor or input " + succOrInput + " in " + n; flood.add(succOrInput); }; for (Node current : flood) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Mon Mar 23 16:11:48 2015 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; @@ -432,14 +433,18 @@ frameState.replaceAndDelete(stateAfterException); } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { handleMissingAfterExceptionFrameState(frameState); + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { + // This is an intrinsic. Deoptimizing within an intrinsic + // must re-execute the intrinsified invocation + assert frameState.outerFrameState() == null; + NodeInputList invokeArgsList = invoke.callTarget().arguments(); + ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]); + FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeArgs); + frameState.replaceAndDelete(stateBeforeCall); } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { - assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; - assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; - assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; - assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState; + assert checkInlineeFrameState(invoke, inlineGraph, frameState); if (outerFrameState == null) { outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind); } @@ -450,6 +455,32 @@ } } + static boolean checkInlineeFrameState(Invoke invoke, StructuredGraph inlineGraph, FrameState frameState) { + assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState; + assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState; + assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState; + if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) { + if (frameState.method().equals(inlineGraph.method())) { + // Normal inlining expects all outermost inlinee frame states to + // denote the inlinee method + } else if (frameState.method().equals(invoke.callTarget().targetMethod())) { + // This occurs when an intrinsic calls back to the original + // method to handle a slow path. During parsing of such a + // partial intrinsic, these calls are given frame states + // that exclude the outer frame state denoting a position + // in the intrinsic code. + assert inlineGraph.method().getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + + frameState; + } else { + throw new AssertionError(frameState.toString()); + } + } + return true; + } + + private static final ValueNode[] NO_ARGS = {}; + private static boolean isStateAfterException(FrameState frameState) { return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized()); } @@ -543,7 +574,7 @@ } public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) { - return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null; + return replacements.getMethodSubstitutionMethod(target) != null || getMacroNodeClass(replacements, target) != null; } public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Mon Mar 23 16:11:48 2015 +0100 @@ -55,18 +55,17 @@ @Override protected Set processBlock(Block block, Set currentState) { + AbstractBeginNode beginNode = block.getBeginNode(); + if (beginNode instanceof AbstractMergeNode) { + AbstractMergeNode abstractMergeNode = (AbstractMergeNode) beginNode; + for (PhiNode phi : abstractMergeNode.phis()) { + if (phi instanceof MemoryPhiNode) { + MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi; + addFloatingReadUsages(currentState, memoryPhiNode); + } + } + } for (Node n : blockToNodesMap.get(block)) { - if (n instanceof AbstractMergeNode) { - AbstractMergeNode abstractMergeNode = (AbstractMergeNode) n; - for (PhiNode phi : abstractMergeNode.phis()) { - if (phi instanceof MemoryPhiNode) { - MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi; - addFloatingReadUsages(currentState, memoryPhiNode); - } - } - - } - if (n instanceof MemoryCheckpoint) { if (n instanceof MemoryCheckpoint.Single) { MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n; @@ -88,7 +87,8 @@ // Floating read was found in the state. currentState.remove(floatingReadNode); } else { - throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule"); + throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule. Block=" + + block + ", block begin: " + block.getBeginNode() + " block loop: " + block.getLoop() + ", " + blockToNodesMap.get(block).get(0)); } } diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon Mar 23 16:11:48 2015 +0100 @@ -150,8 +150,9 @@ } else { Block currentBlock = b; assert currentBlock != null; + Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap); - assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock; + assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock); if (latestBlock != currentBlock) { if (currentNode instanceof FloatingReadNode) { @@ -200,6 +201,12 @@ return watchListMap; } + private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) { + assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format("%s %s %s", + currentNode, earliestBlock, latestBlock); + return true; + } + private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap> blockToNodesMap, NodeMap nodeMap) { for (Block b : cfg.getBlocks()) { List nodes = blockToNodesMap.get(b); @@ -414,9 +421,11 @@ assert currentNode.hasUsages(); for (Node usage : currentNode.usages()) { block = calcBlockForUsage(currentNode, usage, block, currentNodeMap); + assert checkLatestEarliestRelation(currentNode, earliestBlock, block); if (scheduleOutOfLoops) { - while (block.getLoopDepth() > earliestBlock.getLoopDepth()) { + while (block.getLoopDepth() > earliestBlock.getLoopDepth() && block != earliestBlock.getDominator()) { block = block.getDominator(); + assert checkLatestEarliestRelation(currentNode, earliestBlock, block); } } if (block == earliestBlock) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -50,7 +50,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -36,7 +36,6 @@ import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; import com.oracle.graal.word.*; import com.oracle.graal.word.nodes.*; @@ -55,11 +54,9 @@ installer = (ReplacementsImpl) getProviders().getReplacements(); } - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -24,14 +24,25 @@ import org.junit.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.runtime.*; public class ReplacementsParseTest extends GraalCompilerTest { + private static final Object THROW_EXCEPTION_MARKER = new Object() { + @Override + public String toString() { + return "THROW_EXCEPTION_MARKER"; + } + }; + static class TestMethods { static double next(double v) { return Math.nextAfter(v, 1.0); @@ -45,6 +56,14 @@ return Math.nextAfter(x, d); } + static String stringize(Object obj) { + String res = String.valueOf(obj); + if (res.equals(THROW_EXCEPTION_MARKER.toString())) { + // Tests exception throwing from partial intrinsification + throw new RuntimeException("ex: " + obj); + } + return res; + } } @ClassSubstitution(TestMethods.class) @@ -55,6 +74,23 @@ double xx = (x == -0.0 ? 0.0 : x); return Math.nextAfter(xx, d); } + + @MethodSubstitution + static String stringize(Object obj) { + if (obj != null && obj.getClass() == String.class) { + return asNonNullString(obj); + } else { + return stringize(obj); + } + } + + public static String asNonNullString(Object object) { + return asNonNullStringIntrinsic(object, String.class, true, true); + } + + @NodeIntrinsic(PiNode.class) + private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); + } private static boolean substitutionsInstalled; @@ -112,4 +148,23 @@ outArray[i] = TestMethods.nextAfter(inArray[i], direction); } } + + @Test + public void testCallStringize() { + test("callStringize", "a string"); + test("callStringize", THROW_EXCEPTION_MARKER); + test("callStringize", Boolean.TRUE); + } + + public Object callStringize(Object obj) { + return TestMethods.stringize(obj); + } + + @Test + public void testRootCompileStringize() { + ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize"); + test(method, null, "a string"); + test(method, null, Boolean.TRUE); + test(method, null, THROW_EXCEPTION_MARKER); + } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.replacements.test; +import java.util.*; + import org.junit.*; import com.oracle.graal.api.code.*; @@ -230,6 +232,16 @@ return clazz.isInstance(object); } + public static boolean isInstance2(boolean cond, Object object) { + Class clazz; + if (cond) { + clazz = String.class; + } else { + clazz = java.util.HashMap.class; + } + return clazz.isInstance(object); + } + public static boolean isAssignableFrom(Class clazz, Class other) { return clazz.isAssignableFrom(other); } @@ -237,6 +249,7 @@ @Test public void testClassSubstitutions() { testGraph("isInstance"); + testGraph("isInstance2"); testGraph("isAssignableFrom"); for (Class c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) { for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { @@ -244,5 +257,12 @@ test("isAssignableFrom", c, o.getClass()); } } + + test("isInstance2", true, null); + test("isInstance2", false, null); + test("isInstance2", true, "string"); + test("isInstance2", false, "string"); + test("isInstance2", true, new HashMap<>()); + test("isInstance2", false, new HashMap<>()); } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -108,32 +108,34 @@ testGraph("unsafeDirectMemoryRead"); testGraph("unsafeDirectMemoryWrite"); - test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i")); - test("unsafeCompareAndSwapLong", unsafe, supply(() -> new Foo()), fooOffset("l")); - test("unsafeCompareAndSwapObject", unsafe, supply(() -> new Foo()), fooOffset("o")); + long address = unsafe.allocateMemory(8 * Kind.values().length); + for (Unsafe unsafeArg : new Unsafe[]{unsafe, null}) { + test("unsafeCompareAndSwapInt", unsafeArg, supply(() -> new Foo()), fooOffset("i")); + test("unsafeCompareAndSwapLong", unsafeArg, supply(() -> new Foo()), fooOffset("l")); + test("unsafeCompareAndSwapObject", unsafeArg, supply(() -> new Foo()), fooOffset("o")); - test("unsafeGetBoolean", unsafe, supply(() -> new Foo()), fooOffset("z")); - test("unsafeGetByte", unsafe, supply(() -> new Foo()), fooOffset("b")); - test("unsafeGetShort", unsafe, supply(() -> new Foo()), fooOffset("s")); - test("unsafeGetChar", unsafe, supply(() -> new Foo()), fooOffset("c")); - test("unsafeGetInt", unsafe, supply(() -> new Foo()), fooOffset("i")); - test("unsafeGetLong", unsafe, supply(() -> new Foo()), fooOffset("l")); - test("unsafeGetFloat", unsafe, supply(() -> new Foo()), fooOffset("f")); - test("unsafeGetDouble", unsafe, supply(() -> new Foo()), fooOffset("d")); - test("unsafeGetObject", unsafe, supply(() -> new Foo()), fooOffset("o")); + test("unsafeGetBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z")); + test("unsafeGetByte", unsafeArg, supply(() -> new Foo()), fooOffset("b")); + test("unsafeGetShort", unsafeArg, supply(() -> new Foo()), fooOffset("s")); + test("unsafeGetChar", unsafeArg, supply(() -> new Foo()), fooOffset("c")); + test("unsafeGetInt", unsafeArg, supply(() -> new Foo()), fooOffset("i")); + test("unsafeGetLong", unsafeArg, supply(() -> new Foo()), fooOffset("l")); + test("unsafeGetFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f")); + test("unsafeGetDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d")); + test("unsafeGetObject", unsafeArg, supply(() -> new Foo()), fooOffset("o")); - test("unsafePutBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"), true); - test("unsafePutByte", unsafe, supply(() -> new Foo()), fooOffset("b"), (byte) 87); - test("unsafePutShort", unsafe, supply(() -> new Foo()), fooOffset("s"), (short) -93); - test("unsafePutChar", unsafe, supply(() -> new Foo()), fooOffset("c"), 'A'); - test("unsafePutInt", unsafe, supply(() -> new Foo()), fooOffset("i"), 42); - test("unsafePutFloat", unsafe, supply(() -> new Foo()), fooOffset("f"), 58.0F); - test("unsafePutDouble", unsafe, supply(() -> new Foo()), fooOffset("d"), -28736.243465D); - test("unsafePutObject", unsafe, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3"); + test("unsafePutBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"), true); + test("unsafePutByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"), (byte) 87); + test("unsafePutShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"), (short) -93); + test("unsafePutChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"), 'A'); + test("unsafePutInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"), 42); + test("unsafePutFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"), 58.0F); + test("unsafePutDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"), -28736.243465D); + test("unsafePutObject", unsafeArg, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3"); - long address = unsafe.allocateMemory(8 * Kind.values().length); - test("unsafeDirectMemoryRead", unsafe, address); - test("unsafeDirectMemoryWrite", unsafe, address, 0xCAFEBABEDEADBABEL); + test("unsafeDirectMemoryRead", unsafeArg, address); + test("unsafeDirectMemoryWrite", unsafeArg, address, 0xCAFEBABEDEADBABEL); + } unsafe.freeMemory(address); } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Mar 23 16:11:48 2015 +0100 @@ -45,7 +45,7 @@ @Override protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { - return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); } @Test diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Mon Mar 23 16:11:48 2015 +0100 @@ -32,141 +32,109 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; 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.util.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; 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.*; public class BoxingSnippets implements Snippets { - /** - * This snippet inlining policy differs from the default one in that it does normal inlining of - * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution). - */ - public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy { - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return false; - } - } - - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object booleanValueOf(boolean value) { valueOfCounter.inc(); return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object byteValueOf(byte value) { valueOfCounter.inc(); return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object charValueOf(char value) { valueOfCounter.inc(); return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object doubleValueOf(double value) { valueOfCounter.inc(); return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object floatValueOf(float value) { valueOfCounter.inc(); return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object intValueOf(int value) { valueOfCounter.inc(); return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object longValueOf(long value) { valueOfCounter.inc(); return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static Object shortValueOf(short value) { valueOfCounter.inc(); return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic()); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static boolean booleanValue(Boolean value) { valueOfCounter.inc(); return value.booleanValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static byte byteValue(Byte value) { valueOfCounter.inc(); return value.byteValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static char charValue(Character value) { valueOfCounter.inc(); return value.charValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static double doubleValue(Double value) { valueOfCounter.inc(); return value.doubleValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static float floatValue(Float value) { valueOfCounter.inc(); return value.floatValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static int intValue(Integer value) { valueOfCounter.inc(); return value.intValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static long longValue(Long value) { valueOfCounter.inc(); return value.longValue(); } - @Snippet(inlining = BoxingSnippetInliningPolicy.class) + @Snippet public static short shortValue(Short value) { valueOfCounter.inc(); return value.shortValue(); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,52 @@ +/* + * 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.replacements; + +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; + +public final class DefaultInlineInvokePlugin implements InlineInvokePlugin { + private final ReplacementsImpl replacements; + + public DefaultInlineInvokePlugin(ReplacementsImpl replacements) { + this.replacements = replacements; + } + + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { + InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType); + if (inlineInfo == null) { + if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { + return new InlineInfo(method, false, false); + } + } + return inlineInfo; + } + + public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { + replacements.notifyOfNoninlinedInvoke(b, method, invoke); + } +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Mon Mar 23 16:11:48 2015 +0100 @@ -28,16 +28,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; import com.oracle.graal.word.*; /** @@ -50,6 +55,7 @@ protected final Providers providers; protected final StructuredGraph graph; protected final WordTypes wordTypes; + protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins; protected FixedWithNextNode lastFixedNode; private final List structures; @@ -57,10 +63,11 @@ abstract static class Structure { } - public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes) { + public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) { this.providers = providers; this.graph = graph; this.wordTypes = wordTypes; + this.graphBuilderPlugins = graphBuilderPlugins; this.lastFixedNode = graph.start(); structures = new ArrayList<>(); @@ -202,14 +209,28 @@ } /** - * Inlines a given invocation to a method. The graph of the inlined method is - * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and - * method substitutions. + * Inlines a given invocation to a method. The graph of the inlined method is processed in the + * same manner as for snippets and method substitutions. */ public void inline(InvokeNode invoke) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); - ReplacementsImpl replacements = (ReplacementsImpl) providers.getReplacements(); - StructuredGraph calleeGraph = replacements.makeGraph(method, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect); + + MetaAccessProvider metaAccess = providers.getMetaAccess(); + Plugins plugins = new Plugins(graphBuilderPlugins); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + + StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph); + + // Remove all frame states from inlinee + for (Node node : calleeGraph.getNodes()) { + if (node instanceof StateSplit) { + ((StateSplit) node).setStateAfter(null); + } + } + new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph); + InliningUtil.inline(invoke, calleeGraph, false, null); } diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Mar 23 16:11:48 2015 +0100 @@ -25,7 +25,9 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; +import static java.lang.String.*; import java.lang.reflect.*; import java.util.*; @@ -41,10 +43,14 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.Graph.Mark; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; +import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo; +import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext; +import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPhase.Instance; import com.oracle.graal.nodes.*; @@ -53,13 +59,11 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.word.*; -public class ReplacementsImpl implements Replacements { +public class ReplacementsImpl implements Replacements, InlineInvokePlugin { public final Providers providers; public final SnippetReflectionProvider snippetReflection; @@ -77,6 +81,56 @@ this.graphBuilderPlugins = plugins; } + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { + return nodeIntrinsificationPhase.getIntrinsic(method) != null || method.getAnnotation(Word.Operation.class) != null || nodeIntrinsificationPhase.isFoldable(method); + } + + private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough + + /** + * Determines whether a given method should be inlined based on whether it has a substitution or + * whether the inlining context is already within a substitution. + * + * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null + * if it should not be inlined based on substitution related criteria + */ + public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { + ResolvedJavaMethod subst = getMethodSubstitutionMethod(method); + if (subst != null) { + if (b.parsingReplacement() || InlineDuringParsing.getValue()) { + // Forced inlining of intrinsics + return new InlineInfo(subst, true, true); + } + return null; + } + if (b.parsingReplacement()) { + assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName()); + + assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + + if (method.getName().startsWith("$jacoco")) { + throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + + b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this."); + } + + // Force inlining when parsing replacements + return new InlineInfo(method, true, true); + } else { + assert nodeIntrinsificationPhase.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(), + method.format("%h.%n"), b); + } + return null; + } + + public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { + if (b.parsingReplacement()) { + boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null; + Replacement replacement = b.getReplacement(); + assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"), + method.format("%h.%n(%p)")); + } + } + /** * Encapsulates method and macro substitutions for a single class. */ @@ -273,7 +327,7 @@ try (DebugCloseable a = SnippetPreparationTime.start()) { FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal : FrameStateProcessing.CollapseFrameForSingleSideEffect; - StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, inliningPolicy(method), frameStateProcessing); + StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing); Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount()); if (!UseSnippetGraphCache || args != null) { return newGraph; @@ -313,7 +367,7 @@ } StructuredGraph graph = graphs.get(substitute); if (graph == null) { - graph = makeGraph(substitute, null, original, inliningPolicy(substitute), FrameStateProcessing.None); + graph = makeGraph(substitute, null, original, FrameStateProcessing.None); graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); @@ -424,26 +478,6 @@ return originalJavaMethod; } - private static SnippetInliningPolicy createPolicyClassInstance(Class policyClass) { - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - public SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(providers.getMetaAccess()); - } - return createPolicyClassInstance(policyClass); - } - /** * Creates a preprocessed graph for a snippet or method substitution. * @@ -451,11 +485,10 @@ * @param args * @param original the original method if {@code method} is a {@linkplain MethodSubstitution * substitution} otherwise null - * @param policy the inlining policy to use during preprocessing * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled. */ - public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) { - return createGraphMaker(method, original, frameStateProcessing).makeGraph(args, policy); + public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) { + return createGraphMaker(method, original, frameStateProcessing).makeGraph(args); } /** @@ -527,9 +560,9 @@ this.frameStateProcessing = frameStateProcessing; } - public StructuredGraph makeGraph(Object[] args, final SnippetInliningPolicy policy) { + public StructuredGraph makeGraph(Object[] args) { try (Scope s = Debug.scope("BuildSnippetGraph", method)) { - StructuredGraph graph = parseGraph(method, args, policy, 0); + StructuredGraph graph = parseGraph(method, args); if (args == null) { // Cannot have a finalized version of a graph in the cache @@ -603,14 +636,12 @@ return false; } - private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough - - private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { + private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) { StructuredGraph graph = args == null ? replacements.graphCache.get(methodToParse) : null; if (graph == null) { StructuredGraph newGraph = null; try (Scope s = Debug.scope("ParseGraph", methodToParse)) { - newGraph = buildGraph(methodToParse, args, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth); + newGraph = buildGraph(methodToParse, args); } catch (Throwable e) { throw Debug.handle(e); } @@ -662,8 +693,17 @@ protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - ResolvedJavaMethod rootMethodIsReplacement = substitutedMethod == null ? method : substitutedMethod; - return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement); + ReplacementContext initialReplacementContext = null; + if (method.getAnnotation(MethodSubstitution.class) != null) { + // Late inlined intrinsic + initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1); + } else { + // Snippet + assert method.getAnnotation(Snippet.class) != null; + ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; + initialReplacementContext = new ReplacementContext(original, method); + } + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext); } /** @@ -700,67 +740,10 @@ } } - private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) { - assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded"; + private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args) { assert methodToParse.hasBytecodes() : methodToParse; final StructuredGraph graph = buildInitialGraph(methodToParse, args); try (Scope s = Debug.scope("buildGraph", graph)) { - Set doNotInline = null; - for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { - if (doNotInline != null && doNotInline.contains(callTarget)) { - continue; - } - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (substitutedMethod != null && (callee.equals(method) || callee.equals(substitutedMethod))) { - /* - * Ensure that calls to the original method inside of a substitution ends up - * calling it instead of the Graal substitution. - */ - if (substitutedMethod.hasBytecodes()) { - final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod, null); - Mark mark = graph.getMark(); - InliningUtil.inline(callTarget.invoke(), originalGraph, true, null); - for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) { - if (doNotInline == null) { - doNotInline = new HashSet<>(); - } - // We do not want to do further inlining (now) for calls - // in the original method as this can cause unlimited - // recursive inlining given an eager inlining policy such - // as DefaultSnippetInliningPolicy. - doNotInline.add(inlinedCallTarget); - } - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph, null); - } - } else { - Class macroNodeClass = InliningUtil.getMacroNodeClass(replacements, callee); - if (macroNodeClass != null) { - InliningUtil.inlineMacroNode(callTarget.invoke(), callee, macroNodeClass); - } else { - StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(replacements, callee); - if (callTarget.invokeKind().isDirect() && (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) { - StructuredGraph targetGraph; - if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { - targetGraph = intrinsicGraph; - } else { - if (callee.getName().startsWith("$jacoco")) { - throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + callee.format("%H.%n(%p)") + " from " + methodToParse.format("%H.%n(%p)") + - " while preparing replacement " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " + - methodToParse.getDeclaringClass().getSourceFileName() + " should fix this."); - } - targetGraph = parseGraph(callee, null, policy, inliningDepth + 1); - } - Object beforeInlineData = beforeInline(callTarget, targetGraph); - InliningUtil.inline(callTarget.invoke(), targetGraph, true, null); - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, targetGraph, beforeInlineData); - } - } - } - } - - afterInlining(graph); for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) { end.disableSafepoint(); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Mar 23 16:11:48 2015 +0100 @@ -24,11 +24,7 @@ import java.lang.annotation.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.replacements.nodes.*; -import com.oracle.graal.word.*; /** * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering @@ -39,12 +35,6 @@ public @interface Snippet { /** - * Specifies the class defining the inlining policy for this snippet. A - * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied. - */ - Class inlining() default SnippetInliningPolicy.class; - - /** * Specifies whether all FrameStates within this snippet should always be removed. If this is * false, FrameStates are only removed if there are no side-effecting instructions in the * snippet. @@ -52,70 +42,6 @@ boolean removeAllFrameStates() default false; /** - * Guides inlining decisions used when installing a snippet. - */ - public interface SnippetInliningPolicy { - - /** - * Determines if {@code method} should be inlined into {@code caller}. - */ - boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); - - /** - * Determines if {@code method} should be inlined using its replacement graph. - * - * @return true if the replacement graph should be used, false for normal inlining. - */ - boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse); - } - - /** - * The default inlining policy which inlines everything except for methods in any of the - * following categories. - *
    - *
  • {@linkplain Fold foldable} methods
  • - *
  • {@linkplain NodeIntrinsic node intrinsics}
  • - *
  • native methods
  • - *
  • constructors of {@link Throwable} classes
  • - *
- */ - public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { - - private final MetaAccessProvider metaAccess; - - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) { - this.metaAccess = metaAccess; - } - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (method.isNative()) { - return false; - } - if (method.getAnnotation(Fold.class) != null) { - return false; - } - if (method.getAnnotation(NodeIntrinsic.class) != null) { - return false; - } - if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.isConstructor()) { - return false; - } - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - return true; - } - - @Override - public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { - return true; - } - } - - /** * Denotes a snippet parameter representing 0 or more arguments that will be bound during * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet * template creation, its value must be an array whose length specifies the number of arguments diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Mar 23 16:11:48 2015 +0100 @@ -158,7 +158,7 @@ void notifyNewTemplate() { templateCount++; - if (UseSnippetTemplateCache && templateCount > MaxTemplatesPerSnippet) { + if (UseSnippetTemplateCache && templateCount == MaxTemplatesPerSnippet) { PrintStream err = System.err; err.printf("WARNING: Exceeded %d templates for snippet %s%n" + " Adjust maximum with %s system property%n", MaxTemplatesPerSnippet, method.format("%h.%n(%p)"), MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME); diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java Mon Mar 23 16:11:48 2015 +0100 @@ -23,7 +23,6 @@ package com.oracle.graal.replacements; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*; import static com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation.*; import sun.misc.*; @@ -33,7 +32,8 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; @@ -105,7 +105,9 @@ for (Kind kind : new Kind[]{Kind.Int, Kind.Long, Kind.Object}) { Class javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()); b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap)); compareAndSwap.setStateAfter(b.createStateAfter()); @@ -115,7 +117,9 @@ if (getAndSetEnabled(arch)) { r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any()); b.push(kind.getStackKind(), b.append(atomicReadWrite)); atomicReadWrite.setStateAfter(b.createStateAfter()); @@ -124,7 +128,9 @@ }); if (kind != Kind.Object) { r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any()); b.push(kind.getStackKind(), b.append(atomicReadAdd)); atomicReadAdd.setStateAfter(b.createStateAfter()); @@ -150,26 +156,26 @@ Class type = kind.toJavaClass(); Registration r = new Registration(plugins, declaringClass); r.register1("reverseBytes", type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value))); return true; } }); r.register1("bitCount", type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Int, b.append(new BitCountNode(value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value))); return true; } }); r.register2("divideUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { - b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { + b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } }); r.register2("remainderUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) { - b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { + b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); return true; } }); @@ -178,12 +184,12 @@ private static void registerCharacterPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Character.class); r.register1("reverseBytes", char.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { // return (char) (Integer.reverse(i) >> 16); ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32)); - b.push(Kind.Char.getStackKind(), b.append(charCast.canonical(null, value))); + b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value))); return true; } }); @@ -192,12 +198,12 @@ private static void registerShortPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Short.class); r.register1("reverseBytes", short.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { // return (short) (Integer.reverse(i) >> 16); ReverseBytesNode reverse = b.append(new ReverseBytesNode(value)); RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16)))); SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32)); - b.push(Kind.Short.getStackKind(), b.append(charCast.canonical(null, value))); + b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value))); return true; } }); @@ -206,14 +212,14 @@ private static void registerFloatPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Float.class); r.register1("floatToRawIntBits", float.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value))); return true; } }); r.register1("intBitsToFloat", int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Float, b.append(new ReinterpretNode(Kind.Float, value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value))); return true; } }); @@ -222,14 +228,14 @@ private static void registerDoublePlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Double.class); r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value))); return true; } }); r.register1("longBitsToDouble", long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new ReinterpretNode(Kind.Double, value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value))); return true; } }); @@ -238,33 +244,33 @@ private static void registerMathPlugins(Architecture arch, InvocationPlugins plugins) { Registration r = new Registration(plugins, Math.class); r.register1("abs", Float.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("abs", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new AbsNode(value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value))); return true; } }); r.register1("sqrt", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(new SqrtNode(value).canonical(null, value))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value))); return true; } }); if (getAndSetEnabled(arch)) { r.register1("log", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG))); return true; } }); r.register1("log10", Double.TYPE, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { - b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG10))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG10))); return true; } }); @@ -278,7 +284,7 @@ this.condition = condition; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { // the mirroring and negation operations get the condition into canonical form boolean mirror = condition.canonicalMirror(); boolean negate = condition.canonicalNegate(); @@ -312,26 +318,26 @@ r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE)); r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE)); r.register2("divide", int.class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Int, b.append(new UnsignedDivNode(x, y).canonical(null, x, y))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { + b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("divide", long.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Long, b.append(new UnsignedDivNode(x, y).canonical(null, x, y))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { + b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", int.class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Int, b.append(new UnsignedRemNode(x, y).canonical(null, x, y))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { + b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } }); r.register2("remainder", long.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { - b.push(Kind.Long, b.append(new UnsignedRemNode(x, y).canonical(null, x, y))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { + b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); return true; } }); @@ -349,7 +355,8 @@ private static void registerObjectPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Object.class); r.register1("", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + ValueNode object = receiver.get(); if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) { RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object); b.append(registerFinalizer); @@ -363,24 +370,23 @@ private static void registerClassPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Class.class); r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) { - ValueNode nullCheckedType = nullCheckedValue(b, type); - LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object)); - b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) { + LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object)); + b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) { - ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType)); - b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) { + ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType)); + b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null))); return true; } }); r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr, ValueNode object) { - if (rcvr.isConstant() && !rcvr.isNullConstant()) { - ResolvedJavaType type = b.getConstantReflection().asJavaType(rcvr.asConstant()); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { + if (receiver.isConstant()) { + ResolvedJavaType type = b.getConstantReflection().asJavaType(receiver.get().asConstant()); if (type != null && !type.isPrimitive()) { b.push(Kind.Object, b.append(CheckCastNode.create(type, object, null, false, b.getAssumptions()))); return true; @@ -402,7 +408,7 @@ Registration r = new Registration(plugins, Edges.class); for (Class c : new Class[]{Node.class, NodeList.class}) { r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) { ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any())); boolean exactType = false; boolean nonNull = false; @@ -411,7 +417,7 @@ } }); r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) { UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any()); b.append(unsafeStore); unsafeStore.setStateAfter(b.createStateAfter()); @@ -429,7 +435,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { if (b.parsingReplacement()) { ResolvedJavaMethod rootMethod = b.getRootMethod(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { @@ -456,7 +462,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { if (b.parsingReplacement()) { ResolvedJavaMethod rootMethod = b.getRootMethod(); if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { @@ -465,7 +471,7 @@ return false; } } - ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), nullCheckedValue(b, value), kind); + ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind); b.push(kind.getStackKind(), b.append(valueNode)); return true; } @@ -486,12 +492,16 @@ this.isVolatile = isVolatile; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); b.push(returnKind.getStackKind(), b.append(new DirectReadNode(address, returnKind))); return true; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_READ)); } @@ -513,12 +523,16 @@ this.isVolatile = isVolatile; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); b.append(new DirectStoreNode(address, value, kind)); return true; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { + // Emits a null-check for the otherwise unused receiver + unsafe.get(); if (isVolatile) { b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE)); } @@ -535,42 +549,42 @@ private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, GraalDirectives.class); r.register0("deoptimize", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("deoptimizeAndInvalidate", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("inCompiledCode", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Int, b.append(ConstantNode.forInt(1))); return true; } }); r.register0("controlFlowAnchor", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new ControlFlowAnchorNode()); return true; } }); r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { b.push(Kind.Int, b.append(new BranchProbabilityNode(probability, condition))); return true; } }); InvocationPlugin blackholePlugin = new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.append(new BlackholeNode(value)); return true; } @@ -583,7 +597,7 @@ final Kind stackKind = kind.getStackKind(); r.register1("opaque", javaClass, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.push(stackKind, b.append(new OpaqueNode(value))); return true; } @@ -594,7 +608,8 @@ private static void registerJMHBlackholePlugins(InvocationPlugins plugins) { InvocationPlugin blackholePlugin = new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode blackhole, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) { + blackhole.get(); b.append(new BlackholeNode(value)); return true; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultLoopNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultLoopNodeFactory.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import com.oracle.graal.api.runtime.*; +import com.oracle.truffle.api.nodes.*; + +@ServiceProvider(LoopNodeFactory.class) +public class DefaultLoopNodeFactory implements LoopNodeFactory { + + public LoopNode create(RepeatingNode repeatingNode) { + return new OptimizedLoopNode(repeatingNode); + } + +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java Mon Mar 23 16:11:48 2015 +0100 @@ -62,7 +62,7 @@ return false; } OptimizedCallTarget splitTarget = call.getCallTarget(); - int nodeCount = splitTarget.countNonTrivialNodes(); + int nodeCount = splitTarget.getNonTrivialNodeCount(); if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { return false; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java Mon Mar 23 16:11:48 2015 +0100 @@ -55,7 +55,7 @@ if (TruffleCompilerOptions.TruffleSplittingAggressive.getValue()) { return true; } - int size = call.getCallTarget().countNonTrivialNodes(); + int size = call.getCallTarget().getNonTrivialNodeCount(); if (size > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { return false; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Mar 23 16:11:48 2015 +0100 @@ -56,10 +56,28 @@ private final List compilationListeners = new ArrayList<>(); private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener(); + private LoopNodeFactory loopNodeFactory; + public GraalTruffleRuntime() { Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); } + private static T loadPrioritizedServiceProvider(Class clazz) { + ServiceLoader serviceLoader = ServiceLoader.load(clazz, GraalTruffleRuntime.class.getClassLoader()); + T bestFactory = null; + for (T factory : serviceLoader) { + if (bestFactory == null) { + bestFactory = factory; + } else if (factory.getPriority() > bestFactory.getPriority()) { + bestFactory = factory; + } + } + if (bestFactory == null) { + throw new IllegalStateException("Unable to load a factory for " + clazz.getName()); + } + return bestFactory; + } + protected void installDefaultListeners() { TraceCompilationFailureListener.install(this); TraceCompilationListener.install(this); @@ -80,11 +98,15 @@ } @Override - public LoopNode createLoopNode(RepeatingNode repeating) { - if (!(repeating instanceof Node)) { + public LoopNode createLoopNode(RepeatingNode repeatingNode) { + if (!(repeatingNode instanceof Node)) { throw new IllegalArgumentException("Repeating node must be of type Node."); } - return new OptimizedLoopNode(repeating); + if (loopNodeFactory == null) { + loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class); + } + + return loopNodeFactory.create(repeatingNode); } @Override diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/LoopNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/LoopNodeFactory.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import com.oracle.truffle.api.nodes.*; + +public interface LoopNodeFactory extends PrioritizedServiceProvider { + + LoopNode create(RepeatingNode repeatingNode); + +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Mar 23 16:11:48 2015 +0100 @@ -486,16 +486,16 @@ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); } - public final int countNonTrivialNodes() { + public final int getNonTrivialNodeCount() { if (cachedNonTrivialNodeCount == -1) { - cachedNonTrivialNodeCount = calculateNonTrivialNodesImpl(); + cachedNonTrivialNodeCount = calculateNonTrivialNodes(getRootNode()); } return cachedNonTrivialNodeCount; } - private int calculateNonTrivialNodesImpl() { + public static int calculateNonTrivialNodes(Node node) { NonTrivialNodeCountVisitor visitor = new NonTrivialNodeCountVisitor(); - getRootNode().accept(visitor); + node.accept(visitor); return visitor.nodeCount; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -32,15 +32,22 @@ */ public final class OptimizedLoopNode extends LoopNode { - public OptimizedLoopNode(RepeatingNode body) { - super(body); + @Child private RepeatingNode repeatingNode; + + public OptimizedLoopNode(RepeatingNode repeatingNode) { + this.repeatingNode = repeatingNode; + } + + @Override + public RepeatingNode getRepeatingNode() { + return repeatingNode; } @Override public void executeLoop(VirtualFrame frame) { int loopCount = 0; try { - while (executeRepeatingNode(frame)) { + while (repeatingNode.executeRepeating(frame)) { if (CompilerDirectives.inInterpreter()) { loopCount++; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PrioritizedServiceProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PrioritizedServiceProvider.java Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +public interface PrioritizedServiceProvider { + + default int getPriority() { + return 0; + } + +} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Mon Mar 23 16:11:48 2015 +0100 @@ -43,7 +43,7 @@ } private static List createDecisions(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy, CompilerOptions options) { - int nodeCount = sourceTarget.countNonTrivialNodes(); + int nodeCount = sourceTarget.getNonTrivialNodeCount(); List exploredCallSites = exploreCallSites(new ArrayList<>(Arrays.asList(sourceTarget)), nodeCount, policy); return decideInlining(exploredCallSites, policy, nodeCount, options); } @@ -66,7 +66,7 @@ List childCallSites = Collections.emptyList(); double frequency = calculateFrequency(parentTarget, callNode); - int nodeCount = callNode.getCurrentCallTarget().countNonTrivialNodes(); + int nodeCount = callNode.getCurrentCallTarget().getNonTrivialNodeCount(); int recursions = countRecursions(callStack); int deepNodeCount = nodeCount; diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java Mon Mar 23 16:11:48 2015 +0100 @@ -101,7 +101,7 @@ } public static void addASTSizeProperty(OptimizedCallTarget target, Map properties) { - int nodeCount = target.countNonTrivialNodes(); + int nodeCount = target.getNonTrivialNodeCount(); int deepNodeCount = nodeCount; TruffleInlining inlining = target.getInlining(); if (inlining != null) { diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java Mon Mar 23 16:11:48 2015 +0100 @@ -26,9 +26,11 @@ import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.truffle.*; public class HistogramInlineInvokePlugin implements InlineInvokePlugin { @@ -47,7 +49,7 @@ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { InlineInfo inlineInfo = delegate.getInlineInfo(b, method, args, returnType); if (inlineInfo != null) { - currentStatistic = new MethodStatistic(currentStatistic, inlineInfo.methodToInline, graph.getNodeCount(), graph.getNodes(MethodCallTargetNode.TYPE).count()); + currentStatistic = new MethodStatistic(currentStatistic, inlineInfo.methodToInline, countNodes(), countCalls()); } return inlineInfo; } @@ -56,13 +58,25 @@ delegate.postInline(inlinedTargetMethod); if (currentStatistic != null) { - currentStatistic.applyNodeCountAfter(graph.getNodeCount()); - currentStatistic.applyCallsAfter(graph.getNodes(MethodCallTargetNode.TYPE).count()); + currentStatistic.applyNodeCountAfter(countNodes()); + currentStatistic.applyCallsAfter(countCalls()); accept(currentStatistic); currentStatistic = currentStatistic.getParent(); } } + private int countNodes() { + return graph.getNodes().filter(node -> isNonTrivial(node)).count(); + } + + private int countCalls() { + return graph.getNodes(MethodCallTargetNode.TYPE).count(); + } + + private static boolean isNonTrivial(Node node) { + return !(node instanceof VirtualState || node instanceof VirtualObjectNode || node instanceof BeginNode || node instanceof DeoptimizeNode); + } + private void accept(MethodStatistic current) { ResolvedJavaMethod method = current.getMethod(); HistogramInlineInvokePlugin.MethodStatistics statistics = histogram.get(method); @@ -74,12 +88,12 @@ } public void print(OptimizedCallTarget target, PrintStream out) { - out.printf("Truffle expansion histogram for %s", target); + out.printf("Truffle expansion histogram for %s%n", target); out.println(" Invocations = Number of expanded invocations"); - out.println(" Nodes = Number of Graal nodes created for this method during partial evaluation."); + out.println(" Nodes = Number of non-trival Graal nodes created for this method during partial evaluation."); out.println(" Calls = Number of not expanded calls created for this method during partial evaluation."); out.printf(" %-11s |Nodes %5s %5s %5s %8s |Calls %5s %5s %5s %8s | Method Name%n", "Invocations", "Sum", "Min", "Max", "Avg", "Sum", "Min", "Max", "Avg"); - histogram.values().stream().sorted().forEach(statistics -> statistics.print(out)); + histogram.values().stream().filter(statistics -> statistics.shallowCount.getSum() > 0).sorted().forEach(statistics -> statistics.print(out)); } private static class MethodStatistics implements Comparable { @@ -95,16 +109,16 @@ } public void print(PrintStream out) { - out.printf(" %11d | %5d %5d %5d %8.2f | %5d %5d %5d %8.2f | %s%n", // + out.printf(" %11d | %5d %5d %5d %8.2f | %5d %5d %5d %8.2f | %s%n", // count, shallowCount.getSum(), shallowCount.getMin(), shallowCount.getMax(), // shallowCount.getAverage(), callCount.getSum(), callCount.getMin(), callCount.getMax(), // callCount.getAverage(), method.format("%h.%n(%p)")); } public int compareTo(MethodStatistics o) { - int result = (int) (o.shallowCount.getSum() - shallowCount.getSum()); + int result = Long.compare(o.shallowCount.getSum(), shallowCount.getSum()); if (result == 0) { - return o.count - count; + return Integer.compare(o.count, count); } return result; } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -94,10 +94,4 @@ public void lower(LoweringTool tool) { IntegerExactArithmeticSplitNode.lower(tool, this); } - - @NodeIntrinsic - public static native int subtractExact(int a, int b); - - @NodeIntrinsic - public static native long subtractExact(long a, long b); } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Mon Mar 23 16:11:48 2015 +0100 @@ -32,7 +32,8 @@ import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.InvocationPlugins.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -68,9 +69,9 @@ public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, OptimizedAssumption.class); r.register1("isValid", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { - if (arg.isConstant()) { - Constant constant = arg.asConstant(); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + if (receiver.isConstant()) { + Constant constant = receiver.get().asConstant(); OptimizedAssumption assumption = b.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant); b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(assumption.isValid()))); if (assumption.isValid()) { @@ -89,31 +90,31 @@ for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) { Class type = kind.toJavaClass(); r.register2("addExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerAddExactNode(x, y))); return true; } }); r.register2("subtractExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerSubExactNode(x, y))); return true; } }); r.register2("multiplyExact", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerMulExactNode(x, y))); return true; } }); r.register2("multiplyHigh", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new IntegerMulHighNode(x, y))); return true; } }); r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { b.push(kind.getStackKind(), b.append(new UnsignedMulHighNode(x, y))); return true; } @@ -124,47 +125,47 @@ public static void registerCompilerDirectivesPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, CompilerDirectives.class); r.register0("inInterpreter", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false))); return true; } }); r.register0("inCompiledCode", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true))); return true; } }); r.register0("transferToInterpreter", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); return true; } }); r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { return true; } }); r.register1("interpreterOnly", Callable.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { return true; } }); r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { b.push(Kind.Boolean.getStackKind(), b.append(new BranchProbabilityNode(probability, condition))); return true; } }); r.register1("bailout", String.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { throw b.bailout(message.asConstant().toValueString()); } @@ -172,7 +173,7 @@ } }); r.register1("isCompilationConstant", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) { b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true))); } else { @@ -182,7 +183,7 @@ } }); r.register1("materialize", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { b.append(new ForceMaterializeNode(value)); return true; } @@ -190,7 +191,7 @@ r = new Registration(plugins, CompilerAsserts.class); r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ValueNode curValue = value; if (curValue instanceof BoxNode) { BoxNode boxNode = (BoxNode) curValue; @@ -215,7 +216,7 @@ } }); r.register1("neverPartOfCompilation", String.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) { if (message.isConstant()) { String messageString = message.asConstant().toValueString(); b.append(new NeverPartOfCompilationNode(messageString)); @@ -229,14 +230,14 @@ public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) { Registration r = new Registration(plugins, OptimizedCallTarget.class); r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode descriptor, ValueNode args) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode descriptor, ValueNode args) { Class frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class; b.push(Kind.Object, b.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args))); return true; } }); r.register2("castArrayFixedLength", Object[].class, int.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode args, ValueNode length) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode args, ValueNode length) { b.push(Kind.Object, b.append(new PiArrayNode(args, length, args.stamp()))); return true; } @@ -264,8 +265,8 @@ private static void registerMaterialize(Registration r) { r.register1("materialize", Receiver.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode frame) { - b.push(Kind.Object, b.append(new MaterializeFrameNode(GraphBuilderContext.nullCheckedValue(b, frame)))); + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver frame) { + b.push(Kind.Object, b.append(new MaterializeFrameNode(frame.get()))); return true; } }); @@ -273,7 +274,7 @@ private static void registerUnsafeCast(Registration r) { r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() { - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) { if (clazz.isConstant() && nonNull.isConstant()) { ConstantReflectionProvider constantReflection = b.getConstantReflection(); ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant()); @@ -331,7 +332,7 @@ this.returnKind = returnKind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) { if (location.isConstant()) { LocationIdentity locationIdentity; if (location.isNullConstant()) { @@ -356,7 +357,7 @@ this.kind = kind; } - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) { ValueNode locationArgument = location; if (locationArgument.isConstant()) { LocationIdentity locationIdentity; diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.test; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - *

Inserting Extra Nodes into the AST Transparently

- * - *

- * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST - * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra - * functionality upon adoption. - *

- * - *

- * This test demonstrates how node instances of a specific class can be automatically wrapped in - * extra nodes when they are inserted into the AST. - *

- */ -public class OnAdoptTest { - - static class Root extends RootNode { - - @Child private Base child1; - @Child private Base child2; - - public Root(Base child1, Base child2) { - super(null); - this.child1 = child1; - this.child2 = child2; - } - - @Override - public Object execute(VirtualFrame frame) { - return child1.executeInt(frame) + child2.executeInt(frame); - } - - } - - abstract static class Base extends Node { - public abstract int executeInt(VirtualFrame frame); - } - - static class Wrapper extends Base { - - @Child private Base wrappee; - - public Wrapper(Base wrappee) { - this.wrappee = wrappee; - } - - @Override - public int executeInt(VirtualFrame frame) { - return 1 + wrappee.executeInt(frame); - } - - } - - abstract static class GenBase extends Base { - - private final int k; - - public GenBase(int k) { - this.k = k; - } - - @Override - public int executeInt(VirtualFrame frame) { - return k; - } - - } - - static class Gen extends GenBase { - public Gen(int k) { - super(k); - } - } - - static class GenWrapped extends GenBase { - - public GenWrapped(int k) { - super(k); - } - - @Override - protected void onAdopt() { - Wrapper w = new Wrapper(this); - this.replace(w); - } - - } - - @Test - public void testOnInsert() { - TruffleRuntime runtime = Truffle.getRuntime(); - Base b1 = new Gen(11); - Base b2 = new GenWrapped(11); - Root r = new Root(b1, b2); - CallTarget ct = runtime.createCallTarget(r); - Object result = ct.call(); - Assert.assertEquals(23, result); - } - -} diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -29,13 +29,20 @@ public final class DefaultLoopNode extends LoopNode { + @Child private RepeatingNode repeatNode; + public DefaultLoopNode(RepeatingNode repeatNode) { - super(repeatNode); + this.repeatNode = repeatNode; + } + + @Override + public RepeatingNode getRepeatingNode() { + return repeatNode; } @Override public void executeLoop(VirtualFrame frame) { - while (executeRepeatingNode(frame)) { + while (repeatNode.executeRepeating(frame)) { // Empty } } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java Mon Mar 23 16:11:48 2015 +0100 @@ -31,20 +31,8 @@ */ public abstract class LoopNode extends Node { - @Child protected RepeatingNode repeatingNode; - - public LoopNode(RepeatingNode repeatingNode) { - this.repeatingNode = repeatingNode; - } - public abstract void executeLoop(VirtualFrame frame); - protected final boolean executeRepeatingNode(VirtualFrame frame) { - return getRepeatingNode().executeRepeating(frame); - } - - public final RepeatingNode getRepeatingNode() { - return repeatingNode; - } + public abstract RepeatingNode getRepeatingNode(); } diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Mar 23 16:11:48 2015 +0100 @@ -176,15 +176,11 @@ if (newChild == this) { throw new IllegalStateException("The parent of a node can never be the node itself."); } - boolean isInserted = newChild.parent == null; newChild.parent = this; if (TruffleOptions.TraceASTJSON) { JSONHelper.dumpNewChild(this, newChild); } newChild.adoptHelper(); - if (isInserted) { - newChild.onAdopt(); - } } private void adoptHelper() { @@ -201,12 +197,8 @@ if (newChild == this) { throw new IllegalStateException("The parent of a node can never be the node itself."); } - boolean isInserted = newChild.parent == null; newChild.parent = this; newChild.adoptUnadoptedHelper(); - if (isInserted) { - newChild.onAdopt(); - } } private void adoptUnadoptedHelper() { @@ -329,16 +321,6 @@ } /** - * Subclasses of {@link Node} can implement this method to execute extra functionality when a - * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the - * node has been effectively inserted, and it is guaranteed to be called only once for any given - * node. - */ - protected void onAdopt() { - // empty default - } - - /** * Invokes the {@link NodeVisitor#visit(Node)} method for this node and recursively also for all * child nodes. * @@ -575,22 +557,19 @@ private static final Object GIL = new Object(); - private static final ThreadLocal IN_ATOMIC_BLOCK = new ThreadLocal<>(); + private static final ThreadLocal IN_ATOMIC_BLOCK = new ThreadLocal() { + @Override + protected Integer initialValue() { + return 0; + } + }; private static boolean inAtomicBlock() { - Integer value = IN_ATOMIC_BLOCK.get(); - if (value == null) { - return false; - } - return value > 0; + return IN_ATOMIC_BLOCK.get() > 0; } private static boolean enterAtomic() { - Integer currentValue = IN_ATOMIC_BLOCK.get(); - if (currentValue == null) { - currentValue = 0; - } - IN_ATOMIC_BLOCK.set(currentValue + 1); + IN_ATOMIC_BLOCK.set(IN_ATOMIC_BLOCK.get() + 1); return true; } diff -r 422e60a2f4b9 -r 220c494e5088 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 Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Mar 23 16:11:48 2015 +0100 @@ -155,14 +155,20 @@ @Override public void putObject(Node receiver, Object value) { - assert !type.isPrimitive() && value == null || type.isInstance(value); - unsafe.putObject(receiver, offset, value); + if (!type.isPrimitive() && value == null || type.isInstance(value)) { + unsafe.putObject(receiver, offset, value); + } else { + throw new IllegalArgumentException(); + } } @Override public Object getObject(Node receiver) { - assert !type.isPrimitive(); - return unsafe.getObject(receiver, offset); + if (!type.isPrimitive()) { + return unsafe.getObject(receiver, offset); + } else { + throw new IllegalArgumentException(); + } } @Override diff -r 422e60a2f4b9 -r 220c494e5088 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java Mon Mar 23 15:58:36 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java Mon Mar 23 16:11:48 2015 +0100 @@ -24,6 +24,8 @@ */ package com.oracle.truffle.api.utilities; +import com.oracle.truffle.api.nodes.*; + /** * Utility class to speculate on certain properties of values. * @@ -42,7 +44,7 @@ * @see #createIdentityProfile() * @see #createClassProfile() */ -public abstract class ValueProfile { +public abstract class ValueProfile extends NodeCloneable { public abstract T profile(T value); diff -r 422e60a2f4b9 -r 220c494e5088 mx/mx_graal.py --- a/mx/mx_graal.py Mon Mar 23 15:58:36 2015 +0100 +++ b/mx/mx_graal.py Mon Mar 23 16:11:48 2015 +0100 @@ -1425,18 +1425,29 @@ mx.log('TOTAL TIME: ' + '[' + str(allDuration) + ']') class Task: + # None or a list of strings. If not None, only tasks whose title + # matches at least one of the substrings in this list will return + # a non-None value from __enter__. The body of a 'with Task(...) as t' + # statement should check 't' and exit immediately if it is None. + filters = None + def __init__(self, title, tasks=None): - self.start = time.time() + self.tasks = tasks self.title = title - self.end = None - self.duration = None - self.tasks = tasks - mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title) + self.skipped = Task.filters is not None and not any([f in title for f in Task.filters]) + if not self.skipped: + self.start = time.time() + self.end = None + self.duration = None + mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title) def __enter__(self): assert self.tasks is not None, "using Task with 'with' statement requires to pass the tasks list in the constructor" + if self.skipped: + return None return self def __exit__(self, exc_type, exc_value, traceback): - self.tasks.append(self.stop()) + if not self.skipped: + self.tasks.append(self.stop()) def stop(self): self.end = time.time() self.duration = datetime.timedelta(seconds=self.end - self.start) @@ -1481,63 +1492,65 @@ def _basic_gate_body(args, tasks): # Build server-hosted-graal now so we can run the unit tests - with Task('BuildHotSpotGraalHosted: product', tasks): - buildvms(['--vms', 'server', '--builds', 'product']) + with Task('BuildHotSpotGraalHosted: product', tasks) as t: + if t: buildvms(['--vms', 'server', '--builds', 'product']) # Run unit tests on server-hosted-graal with VM('server', 'product'): - with Task('UnitTests:hosted-product', tasks): - unittest(['--enable-timing', '--verbose', '--fail-fast']) + with Task('UnitTests:hosted-product', tasks) as t: + if t: unittest(['--enable-timing', '--verbose', '--fail-fast']) # Build the other VM flavors - with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks): - buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) + with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks) as t: + if t: buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) with VM('graal', 'fastdebug'): - with Task('BootstrapWithSystemAssertions:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-version']) + with Task('BootstrapWithSystemAssertions:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-version']) with VM('graal', 'fastdebug'): - with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version']) + with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version']) with VM('graal', 'fastdebug'): - with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks): - vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version']) + with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks) as t: + if t: vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version']) with VM('graal', 'product'): - with Task('BootstrapWithGCVerification:product', tasks): - out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + with Task('BootstrapWithGCVerification:product', tasks) as t: + if t: + out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) with VM('graal', 'product'): - with Task('BootstrapWithG1GCVerification:product', tasks): - out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write - vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) + with Task('BootstrapWithG1GCVerification:product', tasks) as t: + if t: + out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write + vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out) with VM('graal', 'product'): - with Task('BootstrapWithRegisterPressure:product', tasks): - vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) + with Task('BootstrapWithRegisterPressure:product', tasks) as t: + if t: vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version']) with VM('graal', 'product'): - with Task('BootstrapWithImmutableCode:product', tasks): - vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) + with Task('BootstrapWithImmutableCode:product', tasks) as t: + if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version']) for vmbuild in ['fastdebug', 'product']: for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): with Task(str(test) + ':' + vmbuild, tasks) as t: - if not test.test('graal'): + if t and not test.test('graal'): t.abort(test.name + ' Failed') # ensure -Xbatch still works with VM('graal', 'product'): - with Task('DaCapo_pmd:BatchMode:product', tasks): - dacapo(['-Xbatch', 'pmd']) + with Task('DaCapo_pmd:BatchMode:product', tasks) as t: + if t: dacapo(['-Xbatch', 'pmd']) # ensure -Xcomp still works with VM('graal', 'product'): - with Task('XCompMode:product', tasks): - vm(['-Xcomp', '-version']) + with Task('XCompMode:product', tasks) as t: + if t: vm(['-Xcomp', '-version']) if args.jacocout is not None: jacocoreport([args.jacocout]) @@ -1545,17 +1558,19 @@ global _jacoco _jacoco = 'off' - with Task('CleanAndBuildIdealGraphVisualizer', tasks): - env = _igvFallbackJDK(os.environ) - buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) - mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env) + with Task('CleanAndBuildIdealGraphVisualizer', tasks) as t: + if t: + env = _igvFallbackJDK(os.environ) + buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) + mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env) # Prevent Graal modifications from breaking the standard builds if args.buildNonGraal: - with Task('BuildHotSpotVarieties', tasks): - buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product']) - if mx.get_os() not in ['windows', 'cygwin']: - buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized']) + with Task('BuildHotSpotVarieties', tasks) as t: + if t: + buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product']) + if mx.get_os() not in ['windows', 'cygwin']: + buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized']) for vmbuild in ['product', 'fastdebug']: for theVm in ['client', 'server']: @@ -1563,11 +1578,11 @@ mx.log('The' + theVm + ' VM is not supported on this platform') continue with VM(theVm, vmbuild): - with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks): - dacapo(['pmd']) + with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks) as t: + if t: dacapo(['pmd']) - with Task('UnitTests:' + theVm + ':' + vmbuild, tasks): - unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api']) + with Task('UnitTests:' + theVm + ':' + vmbuild, tasks) as t: + if t: unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api']) def gate(args, gate_body=_basic_gate_body): @@ -1580,61 +1595,67 @@ parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code') parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code') parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM') + parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run') parser.add_argument('--jacocout', help='specify the output directory for jacoco report') args = parser.parse_args(args) global _jacoco + if args.task_filter: + Task.filters = args.task_filter.split(',') tasks = [] total = Task('Gate') try: - with Task('Pylint', tasks): - mx.pylint([]) + with Task('Pylint', tasks) as t: + if t: mx.pylint([]) def _clean(name='Clean'): - with Task(name, tasks): - cleanArgs = [] - if not args.cleanNative: - cleanArgs.append('--no-native') - if not args.cleanJava: - cleanArgs.append('--no-java') - clean(cleanArgs) + with Task(name, tasks) as t: + if t: + cleanArgs = [] + if not args.cleanNative: + cleanArgs.append('--no-native') + if not args.cleanJava: + cleanArgs.append('--no-java') + clean(cleanArgs) _clean() with Task('IDEConfigCheck', tasks): - mx.ideclean([]) - mx.ideinit([]) + if t: + mx.ideclean([]) + mx.ideinit([]) eclipse_exe = mx.get_env('ECLIPSE_EXE') if eclipse_exe is not None: with Task('CodeFormatCheck', tasks) as t: - if mx.eclipseformat(['-e', eclipse_exe]) != 0: + if t and mx.eclipseformat(['-e', eclipse_exe]) != 0: t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush') with Task('Canonicalization Check', tasks) as t: - mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) - if mx.canonicalizeprojects([]) != 0: - t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') + if t: + mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) + if mx.canonicalizeprojects([]) != 0: + t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') if mx.get_env('JDT'): with Task('BuildJavaWithEcj', tasks): - build(['-p', '--no-native', '--jdt-warning-as-error']) + if t: build(['-p', '--no-native', '--jdt-warning-as-error']) _clean('CleanAfterEcjBuild') with Task('BuildJavaWithJavac', tasks): - build(['-p', '--no-native', '--force-javac']) + if t: build(['-p', '--no-native', '--force-javac']) with Task('Checkstyle', tasks) as t: - if mx.checkstyle([]) != 0: + if t and mx.checkstyle([]) != 0: t.abort('Checkstyle warnings were found') with Task('Checkheaders', tasks) as t: - if checkheaders([]) != 0: + if t and checkheaders([]) != 0: t.abort('Checkheaders warnings were found') with Task('FindBugs', tasks) as t: - if findbugs([]) != 0: + if t and findbugs([]) != 0: t.abort('FindBugs warnings were found') if exists('jacoco.exec'): @@ -1663,6 +1684,9 @@ mx.log(' =======') mx.log(' ' + str(total.duration)) + if args.task_filter: + Task.filters = None + def deoptalot(args): """bootstrap a fastdebug Graal VM with DeoptimizeALot and VerifyOops on diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java Mon Mar 23 16:11:48 2015 +0100 @@ -86,7 +86,7 @@ this.to = to; this.state = State.SAME; this.label = label; - this.type = type; + this.type = type.intern(); } static WeakHashMap> immutableCache = new WeakHashMap<>(); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Mon Mar 23 16:11:48 2015 +0100 @@ -271,7 +271,7 @@ } else { sb.append(", "); } - sb.append(p[0] + "=" + p[1]); + sb.append(p[0]).append("=").append(p[1]); } return sb.append("]").toString(); } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Mon Mar 23 16:11:48 2015 +0100 @@ -706,7 +706,8 @@ private void parseNodes(InputGraph graph) throws IOException { int count = readInt(); Map props = new HashMap<>(); - List edges = new LinkedList<>(); + List inputEdges = new ArrayList<>(count); + List succEdges = new ArrayList<>(count); for (int i = 0; i < count; i++) { int id = readInt(); InputNode node = new InputNode(id); @@ -733,7 +734,7 @@ props.put(key, value); } } - int edgesStart = edges.size(); + ArrayList currentEdges = new ArrayList<>(); int portNum = 0; for (TypedPort p : nodeClass.inputs) { if (p.isList) { @@ -741,14 +742,18 @@ for (int j = 0; j < size; j++) { int in = readInt(); if (in >= 0) { - edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true)); + Edge e = new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true); + currentEdges.add(e); + inputEdges.add(e); portNum++; } } } else { int in = readInt(); if (in >= 0) { - edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true)); + Edge e = new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true); + currentEdges.add(e); + inputEdges.add(e); portNum++; } } @@ -761,19 +766,23 @@ for (int j = 0; j < size; j++) { int sux = readInt(); if (sux >= 0) { - edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false)); + Edge e = new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false); + currentEdges.add(e); + succEdges.add(e); portNum++; } } } else { int sux = readInt(); if (sux >= 0) { - edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false)); + Edge e = new Edge(id, sux, (char) portNum, p.name, "Successor", false); + currentEdges.add(e); + succEdges.add(e); portNum++; } } } - properties.setProperty("name", createName(edges.subList(edgesStart, edges.size()), props, nodeClass.nameTemplate)); + properties.setProperty("name", createName(currentEdges, props, nodeClass.nameTemplate)); properties.setProperty("class", nodeClass.className); switch (nodeClass.className) { case "BeginNode": @@ -786,9 +795,20 @@ graph.addNode(node); props.clear(); } - for (Edge e : edges) { - char fromIndex = e.input ? 1 : e.num; - char toIndex = e.input ? e.num : 0; + + Set nodesWithSuccessor = new HashSet<>(); + + for (Edge e : succEdges) { + assert !e.input; + char fromIndex = e.num; + nodesWithSuccessor.add(graph.getNode(e.from)); + char toIndex = 0; + graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type)); + } + for (Edge e : inputEdges) { + assert e.input; + char fromIndex = (char) (nodesWithSuccessor.contains(graph.getNode(e.from)) ? 1 : 0); + char toIndex = e.num; graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type)); } } @@ -805,7 +825,7 @@ case "i": StringBuilder inputString = new StringBuilder(); for(Edge edge : edges) { - if (name.equals(edge.label)) { + if (edge.label.startsWith(name) && (name.length() == edge.label.length() || edge.label.charAt(name.length()) == '[')) { if (inputString.length() > 0) { inputString.append(", "); } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Mon Mar 23 16:11:48 2015 +0100 @@ -75,6 +75,7 @@ public static final String NODE_ID_PROPERTY = "id"; public static final String FROM_PROPERTY = "from"; public static final String TO_PROPERTY = "to"; + public static final String TYPE_PROPERTY = "type"; public static final String PROPERTY_NAME_PROPERTY = "name"; public static final String GRAPH_NAME_PROPERTY = "name"; public static final String FROM_INDEX_PROPERTY = "fromIndex"; @@ -387,6 +388,7 @@ int from = -1; int to = -1; String label = null; + String type = null; try { String fromIndexString = readAttribute(FROM_INDEX_PROPERTY); @@ -403,6 +405,7 @@ } label = readAttribute(LABEL_PROPERTY); + type = readAttribute(TYPE_PROPERTY); from = lookupID(readRequiredAttribute(FROM_PROPERTY)); to = lookupID(readRequiredAttribute(TO_PROPERTY)); @@ -410,7 +413,7 @@ throw new SAXException(e); } - InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, ""); + InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, type == null ? "" : type); return start(conn); } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Mon Mar 23 16:11:48 2015 +0100 @@ -240,6 +240,7 @@ } p.setProperty(Parser.TO_PROPERTY, Integer.toString(edge.getTo())); p.setProperty(Parser.FROM_PROPERTY, Integer.toString(edge.getFrom())); + p.setProperty(Parser.TYPE_PROPERTY, edge.getType()); return p; } } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd Mon Mar 23 16:11:48 2015 +0100 @@ -109,6 +109,7 @@ + diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml Mon Mar 23 16:11:48 2015 +0100 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties Mon Mar 23 16:11:48 2015 +0100 @@ -1,5 +1,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=09ba2a87 -nbproject/build-impl.xml.script.CRC32=19fb08e0 -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=e4293f0e +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml Mon Mar 23 16:11:48 2015 +0100 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties Mon Mar 23 16:11:48 2015 +0100 @@ -4,5 +4,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=79002a09 -nbproject/build-impl.xml.script.CRC32=7ac2ee25 -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=2867f2d5 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml Mon Mar 23 16:11:48 2015 +0100 @@ -23,6 +23,14 @@ + com.sun.hotspot.igv.layout + + + + 1.0 + + + com.sun.hotspot.igv.graph diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,7 +33,6 @@ import java.awt.Color; import java.util.HashMap; import java.util.List; -import java.util.regex.Pattern; /** * Filter that colors usage and successor edges differently. @@ -42,7 +41,7 @@ */ public class GraalEdgeColorFilter extends AbstractFilter { - private HashMap usageColor = new HashMap<>(); + private final HashMap usageColor = new HashMap<>(); private Color otherUsageColor = Color.BLACK; public GraalEdgeColorFilter() { diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -var f = new CombineFilter("Combine Filter"); -f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", ".*"), new Properties.RegexpPropertyMatcher("class", "BeginNode"), false, "shortName")); -f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", "EndNode"), new Properties.RegexpPropertyMatcher("class", ".*"), true, "shortName")); -f.apply(graph); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Mon Mar 23 16:11:48 2015 +0100 @@ -1,5 +1,5 @@ colorize("name", ".*", white); -colorize("name", "Begin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange); +colorize("name", "Begin|KillingBegin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange); colorize("name", "Phi.*|ValueProxy", magenta); colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0)); colorize("name", "If|Merge", pink); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter Mon Mar 23 15:58:36 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -colorize("class", "FrameState", red); -colorize("locks", "", gray); \ No newline at end of file diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter Mon Mar 23 16:11:48 2015 +0100 @@ -0,0 +1,3 @@ +split("class", "ConstantLocationNode"); +split("class", "ParameterNode"); +split("class", "ConstantNode"); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Mon Mar 23 16:11:48 2015 +0100 @@ -18,7 +18,7 @@ - + @@ -26,10 +26,6 @@ - - - - diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Mon Mar 23 16:11:48 2015 +0100 @@ -41,8 +41,9 @@ private InputGraph graph; private int curId; private String nodeText; - private Font font; - private Font slotFont; + private final Font font; + private final Font slotFont; + private final Font boldFont; public Font getFont() { return font; @@ -51,12 +52,17 @@ public Font getSlotFont() { return slotFont; } + + public Font getBoldFont() { + return boldFont; + } private Diagram() { figures = new ArrayList<>(); this.nodeText = ""; - this.font = new Font("Arial", Font.PLAIN, 13); + this.font = new Font("Arial", Font.PLAIN, 12); this.slotFont = new Font("Arial", Font.PLAIN, 10); + this.boldFont = this.font.deriveFont(Font.BOLD); } public String getNodeText() { diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,14 +33,10 @@ import java.util.List; import java.util.*; -/** - * - * @author Thomas Wuerthinger - */ public class Figure extends Properties.Entity implements Source.Provider, Vertex { - public static final int INSET = 12; - public static int SLOT_WIDTH = 12; + public static final int INSET = 8; + public static int SLOT_WIDTH = 10; public static final int OVERLAPPING = 6; public static final int SLOT_START = 4; public static final int SLOT_OFFSET = 8; diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Mon Mar 23 16:11:48 2015 +0100 @@ -43,8 +43,8 @@ public static final int CROSSING_ITERATIONS = 2; public static final int DUMMY_HEIGHT = 1; public static final int DUMMY_WIDTH = 1; - public static final int X_OFFSET = 9; - public static final int LAYER_OFFSET = 30; + public static final int X_OFFSET = 8; + public static final int LAYER_OFFSET = 8; public static final int MAX_LAYER_LENGTH = -1; public static final int MIN_LAYER_DIFFERENCE = 1; public static final int VIP_BONUS = 10; @@ -75,8 +75,6 @@ private LayoutGraph graph; private List[] layers; private int layerCount; - private Set firstLayerHint; - private Set lastLayerHint; private Set importantLinks; private Set linksToFollow; @@ -181,17 +179,15 @@ @Override public void doLayout(LayoutGraph graph) { - doLayout(graph, new HashSet(), new HashSet(), new HashSet()); + doLayout(graph, new HashSet()); } @Override - public void doLayout(LayoutGraph graph, Set firstLayerHint, Set lastLayerHint, Set importantLinks) { + public void doLayout(LayoutGraph graph, Set importantLinks) { this.importantLinks = importantLinks; this.graph = graph; - this.firstLayerHint = firstLayerHint; - this.lastLayerHint = lastLayerHint; vertexToLayoutNode = new HashMap<>(); reversedLinks = new HashSet<>(); @@ -219,7 +215,6 @@ } for (LayoutEdge e : tmpArr) { - //System.out.println("Removed " + e); e.from.succs.remove(e); e.to.preds.remove(e); } @@ -302,8 +297,6 @@ Collections.reverse(points); - - if (cur.vertex == null && cur.preds.size() == 0) { if (reversedLinkEndPoints.containsKey(e.link)) { @@ -364,7 +357,7 @@ LayoutNode cur = e.to; LayoutNode other = e.from; LayoutEdge curEdge = e; - while (cur.vertex == null && cur.succs.size() != 0) { + while (cur.vertex == null && !cur.succs.isEmpty()) { if (points.size() > 1 && points.get(points.size() - 1).x == cur.x + cur.width / 2 && points.get(points.size() - 2).x == cur.x + cur.width / 2) { points.remove(points.size() - 1); } @@ -373,7 +366,7 @@ points.remove(points.size() - 1); } points.add(new Point(cur.x + cur.width / 2, cur.y + cur.height)); - if (cur.succs.size() == 0) { + if (cur.succs.isEmpty()) { break; } assert cur.succs.size() == 1; @@ -381,15 +374,13 @@ cur = curEdge.to; } - p = new Point(cur.x + curEdge.relativeTo, cur.y + cur.yOffset + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y)); points.add(p); if (curEdge.to.inOffsets.containsKey(curEdge.relativeTo)) { points.add(new Point(p.x, p.y + curEdge.to.inOffsets.get(curEdge.relativeTo) + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y))); } - - if (cur.succs.size() == 0 && cur.vertex == null) { + if (cur.succs.isEmpty() && cur.vertex == null) { if (reversedLinkStartPoints.containsKey(e.link)) { for (Point p1 : reversedLinkStartPoints.get(e.link)) { points.add(0, new Point(p1.x + other.x, p1.y + other.y)); @@ -528,13 +519,34 @@ private static final Comparator nodeProcessingDownComparator = new Comparator() { @Override public int compare(LayoutNode n1, LayoutNode n2) { + int n1VIP = 0; + for (LayoutEdge e : n1.preds) { + if (e.vip) { + n1VIP++; + } + } + int n2VIP = 0; + for (LayoutEdge e : n2.preds) { + if (e.vip) { + n2VIP++; + } + } + if (n1VIP != n2VIP) { + return n2VIP - n1VIP; + } if (n1.vertex == null) { if (n2.vertex == null) { return 0; } + if (n1.preds.size() == 1 && n1.preds.get(0).from.vertex != null) { + return 1; + } return -1; } if (n2.vertex == null) { + if (n2.preds.size() == 1 && n2.preds.get(0).from.vertex != null) { + return -1; + } return 1; } return n1.preds.size() - n2.preds.size(); @@ -544,15 +556,36 @@ @Override public int compare(LayoutNode n1, LayoutNode n2) { + int n1VIP = 0; + for (LayoutEdge e : n1.succs) { + if (e.vip) { + n1VIP++; + } + } + int n2VIP = 0; + for (LayoutEdge e : n2.succs) { + if (e.vip) { + n2VIP++; + } + } if (n1.vertex == null) { if (n2.vertex == null) { return 0; } + if (n1.succs.size() == 1 && n1.succs.get(0).to.vertex != null) { + return 1; + } return -1; } if (n2.vertex == null) { + if (n2.succs.size() == 1 && n2.succs.get(0).to.vertex != null) { + return -1; + } return 1; } + if (n1VIP != n2VIP) { + return n2VIP - n1VIP; + } return n1.succs.size() - n2.succs.size(); } }; @@ -568,7 +601,7 @@ n.x = space[n.layer].get(n.pos); } } - + @SuppressWarnings("unchecked") private void createArrays() { space = new ArrayList[layers.length]; @@ -600,13 +633,23 @@ initialPositions(); for (int i = 0; i < SWEEP_ITERATIONS; i++) { sweepDown(); + adjustSpace(); sweepUp(); + adjustSpace(); } - + sweepDown(); - //for (int i = 0; i < SWEEP_ITERATIONS; i++) { - // doubleSweep(); - //} + } + + private void adjustSpace() { + for (int i = 0; i < layers.length; i++) { + // space[i] = new ArrayList<>(); + int curX = 0; + for (LayoutNode n : layers[i]) { + space[i].add(n.x); +// curX += n.width + xOffset; + } + } } private int calculateOptimalDown(LayoutNode n) { @@ -614,22 +657,38 @@ if (size == 0) { return n.x; } - int[] values = new int[size]; - for (int i = 0; i < size; i++) { - LayoutEdge e = n.preds.get(i); - values[i] = e.from.x + e.relativeFrom - e.relativeTo; + int vipCount = 0; + for (LayoutEdge e : n.preds) { if (e.vip) { - return values[i]; + vipCount++; } } - return median(values); + + if (vipCount == 0) { + int[] values = new int[size]; + for (int i = 0; i < size; i++) { + LayoutEdge e = n.preds.get(i); + values[i] = e.from.x + e.relativeFrom - e.relativeTo; + } + return median(values); + } else { + int z = 0; + int[] values = new int[vipCount]; + for (int i = 0; i < size; i++) { + LayoutEdge e = n.preds.get(i); + if (e.vip) { + values[z++] = e.from.x + e.relativeFrom - e.relativeTo; + } + } + return median(values); + } } private int calculateOptimalBoth(LayoutNode n) { if (n.preds.size() == n.succs.size()) { return n.x; } - + int[] values = new int[n.preds.size() + n.succs.size()]; int i = 0; @@ -747,7 +806,7 @@ n.x = pos; } - assert minX <= maxX; + assert minX <= maxX : minX + " vs " + maxX; } treeSet.add(n); @@ -769,7 +828,7 @@ assert n.layer < layerCount; } } - + @SuppressWarnings("unchecked") private void createLayers() { layers = new List[layerCount]; @@ -789,7 +848,7 @@ if (n.layer == 0) { layers[0].add(n); visited.add(n); - } else if (n.preds.size() == 0) { + } else if (n.preds.isEmpty()) { layers[n.layer].add(n); visited.add(n); } @@ -806,7 +865,6 @@ } } - updatePositions(); initX(); @@ -816,11 +874,7 @@ downSweep(); upSweep(); } - if (reversedLinks.isEmpty()) { - // This graph seems to be a tree or forest. - // A final down-sweep will usually give us a better layout. - downSweep(); - } + downSweep(); } private void initX() { @@ -869,8 +923,8 @@ if (e.vip) { factor = VIP_BONUS; } - sum += cur*factor; - count+=factor; + sum += cur * factor; + count += factor; } if (count > 0) { @@ -879,7 +933,6 @@ } } - updateCrossingNumbers(i, true); Collections.sort(layers[i], crossingNodeComparator); updateXOfLayer(i); @@ -940,8 +993,8 @@ if (e.vip) { factor = VIP_BONUS; } - sum += cur*factor; - count+=factor; + sum += cur * factor; + count += factor; } if (count > 0) { @@ -1012,7 +1065,7 @@ } curY += maxHeight + baseLine + bottomBaseLine; - curY += layerOffset + (int) Math.sqrt(maxXOffset); + curY += layerOffset + ((int) (Math.sqrt(maxXOffset) * 1.5)); } } } @@ -1041,7 +1094,6 @@ protected void run() { oldNodeCount = nodes.size(); - if (combine == Combine.SAME_OUTPUTS) { Comparator comparator = new Comparator() { @@ -1154,7 +1206,6 @@ maxLayer = Math.max(maxLayer, curEdge.to.layer); } - int cnt = maxLayer - n.layer - 1; LayoutEdge[] edges = new LayoutEdge[cnt]; LayoutNode[] nodes = new LayoutNode[cnt]; @@ -1279,91 +1330,109 @@ @Override protected void run() { - - List insertOrder = new ArrayList<>(); + assignLayerDownwards(); + assignLayerUpwards(); + } - HashSet set = new HashSet<>(); + private void assignLayerDownwards() { + ArrayList hull = new ArrayList<>(); for (LayoutNode n : nodes) { - if (n.preds.size() == 0) { - set.add(n); - insertOrder.add(n); + if (n.preds.isEmpty()) { + hull.add(n); n.layer = 0; } } int z = minLayerDifference; - HashSet newSet = new HashSet<>(); - HashSet failed = new HashSet<>(); - while (!set.isEmpty()) { - - newSet.clear(); - failed.clear(); - - for (LayoutNode n : set) { - + while (!hull.isEmpty()) { + ArrayList newSet = new ArrayList<>(); + for (LayoutNode n : hull) { for (LayoutEdge se : n.succs) { LayoutNode s = se.to; - if (!newSet.contains(s) && !failed.contains(s)) { - boolean ok = true; + if (s.layer != -1) { + // This node was assigned before. + } else { + boolean unassignedPred = false; for (LayoutEdge pe : s.preds) { LayoutNode p = pe.from; - if (p.layer == -1) { - ok = false; + if (p.layer == -1 || p.layer >= z) { + // This now has an unscheduled successor or a successor that was scheduled only in this round. + unassignedPred = true; break; } } - if (ok) { + if (unassignedPred) { + // This successor node can not yet be assigned. + } else { + s.layer = z; newSet.add(s); - } else { - failed.add(s); } } } - } - for (LayoutNode n : newSet) { - n.layer = z; - insertOrder.add(n); - } - - // Swap sets - HashSet tmp = set; - set = newSet; - newSet = tmp; + hull = newSet; z += minLayerDifference; } - optimize(insertOrder); + layerCount = z - minLayerDifference; + for (LayoutNode n : nodes) { + n.layer = (layerCount - 1 - n.layer); + } + } + + private void assignLayerUpwards() { + ArrayList hull = new ArrayList<>(); + for (LayoutNode n : nodes) { + if (n.succs.isEmpty()) { + hull.add(n); + } else { + n.layer = -1; + } + } + + int z = minLayerDifference; + while (!hull.isEmpty()) { + ArrayList newSet = new ArrayList<>(); + for (LayoutNode n : hull) { + if (n.layer < z) { + for (LayoutEdge se : n.preds) { + LayoutNode s = se.from; + if (s.layer != -1) { + // This node was assigned before. + } else { + boolean unassignedSucc = false; + for (LayoutEdge pe : s.succs) { + LayoutNode p = pe.to; + if (p.layer == -1 || p.layer >= z) { + // This now has an unscheduled successor or a successor that was scheduled only in this round. + unassignedSucc = true; + break; + } + } + + if (unassignedSucc) { + // This predecessor node can not yet be assigned. + } else { + s.layer = z; + newSet.add(s); + } + } + } + } else { + newSet.add(n); + } + } + + hull = newSet; + z += minLayerDifference; + } layerCount = z - minLayerDifference; - for (Vertex v : lastLayerHint) { - - LayoutNode n = vertexToLayoutNode.get(v); - assert n.succs.size() == 0; - n.layer = layerCount - 1; - } - - for (Vertex v : firstLayerHint) { - LayoutNode n = vertexToLayoutNode.get(v); - assert n.preds.size() == 0; - n.layer = 0; - assert n.layer == 0; - } - } - - public void optimize(List insertOrder) { - for (int i = insertOrder.size() - 1; i >= 0; i--) { - LayoutNode cur = insertOrder.get(i); - if (cur.succs.size() > cur.preds.size()) { - int minLayer = cur.succs.get(0).to.layer; - for (LayoutEdge e : cur.succs) { - minLayer = Math.min(minLayer, e.to.layer); - } - cur.layer = minLayer - 1; - } + for (LayoutNode n : nodes) { + n.layer = (layerCount - 1 - n.layer); } } @@ -1415,7 +1484,6 @@ } } - // Start DFS and reverse back edges visited = new HashSet<>(); active = new HashSet<>(); @@ -1423,7 +1491,6 @@ DFS(node); } - for (LayoutNode node : nodes) { SortedSet reversedDown = new TreeSet<>(); @@ -1434,7 +1501,6 @@ } } - SortedSet reversedUp = null; if (reversedDown.size() == 0) { reversedUp = new TreeSet<>(Collections.reverseOrder()); @@ -1522,7 +1588,6 @@ curX += offset; node.bottomYOffset += offset; - endPoints.add(new Point(pos, node.height)); endPoints.add(new Point(pos, oldNodeHeight)); for (LayoutEdge e : reversedPreds) { @@ -1530,7 +1595,6 @@ } } - if (minX < 0) { for (LayoutEdge e : node.preds) { e.relativeTo -= minX; @@ -1650,6 +1714,13 @@ @Override public int compare(Link l1, Link l2) { + if (l1.isVIP() && !l2.isVIP()) { + return -1; + } + + if (!l1.isVIP() && l2.isVIP()) { + return 1; + } int result = l1.getFrom().getVertex().compareTo(l2.getFrom().getVertex()); if (result != 0) { @@ -1698,15 +1769,15 @@ edge.relativeFrom = l.getFrom().getRelativePosition().x; edge.relativeTo = l.getTo().getRelativePosition().x; edge.link = l; + edge.vip = l.isVIP(); edge.from.succs.add(edge); edge.to.preds.add(edge); - edge.vip = l.isVIP(); - //assert edge.from != edge.to; // No self-loops allowed + //assert edge.from != edge.to; // No self-loops allowed } for (Link l : importantLinks) { - if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) || - vertexToLayoutNode.containsKey(l.getTo().getVertex())) { + if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) + || vertexToLayoutNode.containsKey(l.getTo().getVertex())) { continue; } LayoutNode from = vertexToLayoutNode.get(l.getFrom().getVertex()); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java Mon Mar 23 16:11:48 2015 +0100 @@ -33,7 +33,7 @@ public void doLayout(LayoutGraph graph); - public void doLayout(LayoutGraph graph, Set firstLayerHint, Set lastLayerHint, Set importantLinks); + public void doLayout(LayoutGraph graph, Set importantLinks); public void doRouting(LayoutGraph graph); } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml --- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml Mon Mar 23 16:11:48 2015 +0100 @@ -4,6 +4,13 @@ *** EDIT ../build.xml INSTEAD *** --> + + + + + + + You must set 'suite.dir' to point to your containing module suite @@ -16,13 +23,21 @@ + + + + + + + - - + + + - + diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties Mon Mar 23 16:11:48 2015 +0100 @@ -1,5 +1,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=13553862 -nbproject/build-impl.xml.script.CRC32=5dca457e -nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1 +nbproject/build-impl.xml.script.CRC32=3db87c68 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1 diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java --- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java Mon Mar 23 16:11:48 2015 +0100 @@ -34,7 +34,7 @@ */ public class ColorIcon implements Icon { - private Color color; + private final Color color; public ColorIcon(Color c) { color = c; @@ -42,8 +42,10 @@ @Override public void paintIcon(Component c, Graphics g, int x, int y) { + Color oldColor = g.getColor(); g.setColor(color); g.fillRect(x, y, 16, 16); + g.setColor(oldColor); } @Override diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Mon Mar 23 16:11:48 2015 +0100 @@ -71,6 +71,7 @@ private Lookup lookup; private InstanceContent content; private Action[] actions; + private Action[] actionsWithSelection; private LayerWidget connectionLayer; private JScrollPane scrollPane; private UndoRedo.Manager undoRedoManager; @@ -100,7 +101,7 @@ public static final float ZOOM_MAX_FACTOR = 3.0f; public static final float ZOOM_MIN_FACTOR = 0.0f;//0.15f; public static final float ZOOM_INCREMENT = 1.5f; - public static final int SLOT_OFFSET = 6; + public static final int SLOT_OFFSET = 8; public static final int ANIMATION_LIMIT = 40; private PopupMenuProvider popupMenuProvider = new PopupMenuProvider() { @@ -374,9 +375,10 @@ } }; - public DiagramScene(Action[] actions, DiagramViewModel model) { + public DiagramScene(Action[] actions, Action[] actionsWithSelection, DiagramViewModel model) { this.actions = actions; + this.actionsWithSelection = actionsWithSelection; content = new InstanceContent(); lookup = new AbstractLookup(content); @@ -399,6 +401,9 @@ blockLayer = new LayerWidget(this); this.addChild(blockLayer); + connectionLayer = new LayerWidget(this); + this.addChild(connectionLayer); + mainLayer = new LayerWidget(this); this.addChild(mainLayer); @@ -410,9 +415,6 @@ bottomRight.setPreferredLocation(new Point(-BORDER_SIZE, -BORDER_SIZE)); this.addChild(bottomRight); - connectionLayer = new LayerWidget(this); - this.addChild(connectionLayer); - LayerWidget selectionLayer = new LayerWidget(this); this.addChild(selectionLayer); @@ -451,12 +453,21 @@ } public boolean isAllVisible() { - return getModel().getHiddenNodes().size() == 0; + return getModel().getHiddenNodes().isEmpty(); } public Action createGotoAction(final Figure f) { final DiagramScene diagramScene = this; - Action a = new AbstractAction() { + String name = f.getLines()[0]; + + name += " ("; + + final boolean hidden = !this.getWidget(f, FigureWidget.class).isVisible(); + if (hidden) { + name += "hidden"; + } + name += ")"; + Action a = new AbstractAction(name, new ColorIcon(f.getColor())) { @Override public void actionPerformed(ActionEvent e) { @@ -465,16 +476,6 @@ }; a.setEnabled(true); - a.putValue(Action.SMALL_ICON, new ColorIcon(f.getColor())); - String name = f.getLines()[0]; - - name += " ("; - - if (!this.getWidget(f, FigureWidget.class).isVisible()) { - name += "hidden"; - } - name += ")"; - a.putValue(Action.NAME, name); return a; } @@ -538,8 +539,6 @@ } private void smallUpdate(boolean relayout) { - - System.out.println("smallUpdate " + relayout); this.updateHiddenNodes(model.getHiddenNodes(), relayout); boolean b = this.getUndoRedoEnabled(); this.setUndoRedoEnabled(false); @@ -559,8 +558,6 @@ } private void relayout(Set oldVisibleWidgets) { - System.out.println("relayout called with old visible widgets: " + oldVisibleWidgets); - Diagram diagram = getModel().getDiagramToView(); HashSet
figures = new HashSet<>(); @@ -589,8 +586,6 @@ private void relayoutWithoutLayout(Set oldVisibleWidgets) { - System.out.println("relayout without layout with visible widgets: " + oldVisibleWidgets); - Diagram diagram = getModel().getDiagramToView(); int maxX = -BORDER_SIZE; @@ -958,8 +953,6 @@ private void updateHiddenNodes(Set newHiddenNodes, boolean doRelayout) { - System.out.println("newHiddenNodes: " + newHiddenNodes); - Diagram diagram = getModel().getDiagramToView(); assert diagram != null; @@ -1027,7 +1020,7 @@ private void showFigure(Figure f) { HashSet newHiddenNodes = new HashSet<>(getModel().getHiddenNodes()); newHiddenNodes.removeAll(f.getSource().getSourceNodesAsSet()); - updateHiddenNodes(newHiddenNodes, true); + this.model.setHiddenNodes(newHiddenNodes); } public void show(final Figure f) { @@ -1062,7 +1055,12 @@ public JPopupMenu createPopupMenu() { JPopupMenu menu = new JPopupMenu(); - for (Action a : actions) { + + Action[] currentActions = actionsWithSelection; + if (this.getSelectedObjects().isEmpty()) { + currentActions = actions; + } + for (Action a : currentActions) { if (a == null) { menu.addSeparator(); } else { diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Mon Mar 23 16:11:48 2015 +0100 @@ -246,7 +246,7 @@ if (last == null) { curColor = Color.green; } else { - if (last.equals(cur)) { + if (last.equals(cur) && last.getProperties().equals(cur.getProperties())) { if (curColor == Color.black) { curColor = Color.white; } @@ -268,7 +268,6 @@ } public void showNot(final Set nodes) { - System.out.println("Shownot called with " + nodes); setHiddenNodes(nodes); } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java Mon Mar 23 16:11:48 2015 +0100 @@ -178,12 +178,17 @@ null, ZoomInAction.get(ZoomInAction.class), ZoomOutAction.get(ZoomOutAction.class), + }; + + + Action[] actionsWithSelection = new Action[]{ + ExtractAction.get(ExtractAction.class), + ShowAllAction.get(HideAction.class), null, ExpandPredecessorsAction.get(ExpandPredecessorsAction.class), ExpandSuccessorsAction.get(ExpandSuccessorsAction.class) }; - initComponents(); ToolbarPool.getDefault().setPreferredIconSize(16); @@ -201,7 +206,7 @@ JScrollPane pane = new JScrollPane(rangeSlider, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); container.add(BorderLayout.CENTER, pane); - scene = new DiagramScene(actions, rangeSliderModel); + scene = new DiagramScene(actions, actionsWithSelection, rangeSliderModel); content = new InstanceContent(); graphContent = new InstanceContent(); this.associateLookup(new ProxyLookup(new Lookup[]{scene.getLookup(), new AbstractLookup(graphContent), new AbstractLookup(content)})); diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Mon Mar 23 16:11:48 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,11 +62,7 @@ public class FigureWidget extends Widget implements Properties.Provider, PopupMenuProvider, DoubleClickHandler { public static final boolean VERTICAL_LAYOUT = true; - //public static final int MAX_STRING_LENGTH = 20; private static final double LABEL_ZOOM_FACTOR = 0.3; - private static final double ZOOM_FACTOR = 0.1; - private Font font; - private Font boldFont; private Figure figure; private Widget leftWidget; private Widget rightWidget; @@ -74,7 +70,7 @@ private ArrayList labelWidgets; private DiagramScene diagramScene; private boolean boundary; - private Node node; + private final Node node; private Widget dummyTop; public void setBoundary(boolean b) { @@ -89,11 +85,10 @@ return node; } - @Override - public boolean isHitAt(Point localLocation) { - return middleWidget.isHitAt(localLocation); - } - + @Override + public boolean isHitAt(Point localLocation) { + return middleWidget.isHitAt(localLocation); + } public FigureWidget(final Figure f, WidgetAction hoverAction, WidgetAction selectAction, DiagramScene scene, Widget parent) { @@ -103,23 +98,20 @@ assert this.getScene().getView() != null; this.figure = f; - font = f.getDiagram().getFont(); - boldFont = f.getDiagram().getFont().deriveFont(Font.BOLD); this.setCheckClipping(true); this.diagramScene = scene; parent.addChild(this); - Widget outer = new Widget(scene); - outer.setBackground(f.getColor()); - outer.setLayout(LayoutFactory.createOverlayLayout()); - + Widget outer = new Widget(scene); + outer.setBackground(f.getColor()); + outer.setLayout(LayoutFactory.createOverlayLayout()); + middleWidget = new Widget(scene); middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.CENTER, 0)); middleWidget.setBackground(f.getColor()); middleWidget.setOpaque(true); - //middleWidget.setBorder(BorderFactory.createLineBorder(Color.BLACK)); middleWidget.getActions().addAction(new DoubleClickAction(this)); - middleWidget.setCheckClipping(true); + middleWidget.setCheckClipping(true); labelWidgets = new ArrayList<>(); @@ -129,7 +121,6 @@ dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1)); middleWidget.addChild(dummyTop); - for (String cur : strings) { String displayString = cur; @@ -138,11 +129,11 @@ labelWidgets.add(lw); middleWidget.addChild(lw); lw.setLabel(displayString); - lw.setFont(font); + lw.setFont(figure.getDiagram().getFont()); lw.setForeground(Color.BLACK); lw.setAlignment(LabelWidget.Alignment.CENTER); lw.setVerticalAlignment(LabelWidget.VerticalAlignment.CENTER); - lw.setBorder(BorderFactory.createEmptyBorder()); + lw.setBorder(BorderFactory.createEmptyBorder()); } Widget dummyBottom = new Widget(scene); @@ -150,7 +141,6 @@ middleWidget.addChild(dummyBottom); middleWidget.setPreferredBounds(new Rectangle(0, Figure.SLOT_WIDTH - Figure.OVERLAPPING, f.getWidth(), f.getHeight())); - //outer.addChild(middleWidget); this.addChild(middleWidget); // Initialize node for property sheet @@ -178,49 +168,22 @@ protected void notifyStateChanged(ObjectState previousState, ObjectState state) { super.notifyStateChanged(previousState, state); - Color borderColor = Color.BLACK; - Color innerBorderColor = getFigure().getColor(); - int thickness = 1; - boolean repaint = false; - Font f = font; - if (state.isSelected() || state.isHighlighted()) { - thickness = 2; - } - if(state.isSelected()) { - f = boldFont; - innerBorderColor = borderColor; - } else { - } - - if (state.isHighlighted()) { - innerBorderColor = borderColor = Color.BLUE; - repaint = true; - } else { - repaint = true; - } - - if (state.isHovered() != previousState.isHovered()) { - - /* - if (state.isHovered()) { - diagramScene.addAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet()); - } else { - diagramScene.removeAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet()); - }*/ - repaint = true; + Font font = this.figure.getDiagram().getFont(); + if (state.isSelected()) { + font = this.figure.getDiagram().getBoldFont(); } - if (state.isSelected() != previousState.isSelected()) { - repaint = true; + Color borderColor = Color.BLACK; + Color innerBorderColor = getFigure().getColor(); + if (state.isHighlighted()) { + innerBorderColor = borderColor = Color.BLUE; } - if (repaint) { - middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1))); - for (LabelWidget labelWidget : labelWidgets) { - labelWidget.setFont(f); - } - repaint(); + middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1))); + for (LabelWidget labelWidget : labelWidgets) { + labelWidget.setFont(font); } + repaint(); } public String getName() { @@ -246,7 +209,6 @@ } if (diagramScene.getZoomFactor() < LABEL_ZOOM_FACTOR) { - for (LabelWidget labelWidget : labelWidgets) { labelWidget.setVisible(false); } @@ -263,19 +225,15 @@ getScene().getGraphics().setComposite(oldComposite); } } - + @Override public JPopupMenu getPopupMenu(Widget widget, Point point) { JPopupMenu menu = diagramScene.createPopupMenu(); menu.addSeparator(); - - JMenu predecessors = new JMenu("Nodes Above"); - predecessors.addMenuListener(new NeighborMenuListener(predecessors, getFigure(), false)); - menu.add(predecessors); - - JMenu successors = new JMenu("Nodes Below"); - successors.addMenuListener(new NeighborMenuListener(successors, getFigure(), true)); - menu.add(successors); + + build(menu, getFigure(), this, false, diagramScene); + menu.addSeparator(); + build(menu, getFigure(), this, true, diagramScene); if (getFigure().getSubgraphs() != null) { menu.addSeparator(); @@ -283,7 +241,7 @@ menu.add(subgraphs); final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class); - for(final InputGraph subgraph : getFigure().getSubgraphs()) { + for (final InputGraph subgraph : getFigure().getSubgraphs()) { Action a = new AbstractAction() { @Override @@ -301,10 +259,45 @@ return menu; } + public static void build(JPopupMenu menu, Figure figure, FigureWidget figureWidget, boolean successors, DiagramScene diagramScene) { + Set
set = figure.getPredecessorSet(); + if (successors) { + set = figure.getSuccessorSet(); + } + + boolean first = true; + for (Figure f : set) { + if (f == figure) { + continue; + } + + if (first) { + first = false; + } else { + menu.addSeparator(); + } + + Action go = diagramScene.createGotoAction(f); + menu.add(go); + + JMenu preds = new JMenu("Nodes Above"); + preds.addMenuListener(figureWidget.new NeighborMenuListener(preds, f, false)); + menu.add(preds); + + JMenu succs = new JMenu("Nodes Below"); + succs.addMenuListener(figureWidget.new NeighborMenuListener(succs, f, true)); + menu.add(succs); + } + + if (figure.getPredecessorSet().isEmpty() && figure.getSuccessorSet().isEmpty()) { + menu.add("(none)"); + } + } + /** * Builds the submenu for a figure's neighbors on demand. */ - private class NeighborMenuListener implements MenuListener { + public class NeighborMenuListener implements MenuListener { private final JMenu menu; private final Figure figure; @@ -323,38 +316,7 @@ return; } - Set
set = figure.getPredecessorSet(); - if (successors) { - set = figure.getSuccessorSet(); - } - - boolean first = true; - for (Figure f : set) { - if (f == figure) { - continue; - } - - if (first) { - first = false; - } else { - menu.addSeparator(); - } - - Action go = diagramScene.createGotoAction(f); - menu.add(go); - - JMenu preds = new JMenu("Nodes Above"); - preds.addMenuListener(new NeighborMenuListener(preds, f, false)); - menu.add(preds); - - JMenu succs = new JMenu("Nodes Below"); - succs.addMenuListener(new NeighborMenuListener(succs, f, true)); - menu.add(succs); - } - - if (menu.getItemCount() == 0) { - menu.add("(none)"); - } + build(menu.getPopupMenu(), figure, FigureWidget.this, successors, diagramScene); } @Override diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java Mon Mar 23 16:11:48 2015 +0100 @@ -109,7 +109,6 @@ if (connections.size() > 0) { color = connections.get(0).getColor(); } - this.setToolTipText("" + generateToolTipText(this.connections) + ""); this.setCheckClipping(true); @@ -203,7 +202,7 @@ g.drawLine(from.x, from.y, to.x, to.y); boolean sameFrom = false; - boolean sameTo = successors.size() == 0; + boolean sameTo = successors.isEmpty(); for (LineWidget w : successors) { if (w.getFrom().equals(getTo())) { sameTo = true; diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java Mon Mar 23 16:11:48 2015 +0100 @@ -41,12 +41,9 @@ public OutputSlotWidget(OutputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) { super(slot, scene, parent, fw); outputSlot = slot; - //init(); - //getFigureWidget().getRightWidget().addChild(this); Point p = outputSlot.getRelativePosition(); p.y += getSlot().getFigure().getHeight() - Figure.SLOT_START; p.x -= this.calculateClientArea().width / 2; - //p.x += this.calculateClientArea().width / 2; this.setPreferredLocation(p); } @@ -56,21 +53,9 @@ @Override protected int calculateSlotWidth() { - List slots = getSlot().getFigure().getOutputSlots(); assert slots.contains(getSlot()); return calculateWidth(slots.size()); } - /* - protected Point calculateRelativeLocation() { - if (getFigureWidget().getBounds() == null) { - return new Point(0, 0); - } - - double x = this.getFigureWidget().getBounds().width; - List slots = outputSlot.getFigure().getOutputSlots(); - assert slots.contains(outputSlot); - return new Point((int) x, (int) (calculateRelativeY(slots.size(), slots.indexOf(outputSlot)))); - }*/ } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java Mon Mar 23 16:11:48 2015 +0100 @@ -59,17 +59,16 @@ this.setToolTipText("" + slot.getToolTipText() + ""); this.setCheckClipping(true); parent.addChild(this); - + //this.setPreferredBounds(this.calculateClientArea()); } - - + @Override protected void notifyStateChanged(ObjectState previousState, ObjectState state) { super.notifyStateChanged(previousState, state); - repaint(); + repaint(); } - + public Slot getSlot() { return slot; } @@ -86,58 +85,59 @@ } Graphics2D g = this.getGraphics(); - // g.setColor(Color.DARK_GRAY); + // g.setColor(Color.DARK_GRAY); int w = this.getBounds().width; int h = this.getBounds().height; - if(getSlot().getSource().getSourceNodes().size() > 0) { + if (getSlot().getSource().getSourceNodes().size() > 0) { final int SMALLER = 0; g.setColor(getSlot().getColor()); int FONT_OFFSET = 2; - + int s = h - SMALLER; int rectW = s; - + Font font = this.getSlot().getFigure().getDiagram().getSlotFont(); - if(this.getState().isSelected()) { + if (this.getState().isSelected()) { font = font.deriveFont(Font.BOLD); } - + if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0) { g.setFont(font); Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g); - rectW = (int)r1.getWidth() + FONT_OFFSET * 2; + rectW = (int) r1.getWidth() + FONT_OFFSET * 2; } - g.fillRect(w/2 - rectW/2, 0, rectW-1, s-1); - - if(this.getState().isHighlighted()) { + g.fillRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1); + + if (this.getState().isHighlighted()) { g.setColor(Color.BLUE); } else { g.setColor(Color.BLACK); } - g.drawRect(w/2 - rectW/2, 0, rectW-1, s-1); - - + g.drawRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1); + if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0 && getScene().getZoomFactor() >= TEXT_ZOOM_FACTOR) { Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g); - g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent()-1);//(int) (r1.getHeight())); + g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent() - 1);//(int) (r1.getHeight())); } - + } else { - if(this.getState().isHighlighted()) { - g.setColor(Color.BLUE); + if (this.getSlot().getConnections().isEmpty()) { + if (this.getState().isHighlighted()) { + g.setColor(Color.BLUE); + } else { + g.setColor(Color.BLACK); + } + int r = 2; + if (slot instanceof OutputSlot) { + g.fillOval(w / 2 - r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2 * r, 2 * r); + } else { + g.fillOval(w / 2 - r, Figure.SLOT_START - r, 2 * r, 2 * r); + } } else { - g.setColor(Color.BLACK); - } - int r = 2; - if (slot instanceof OutputSlot) { - g.fillOval(w/2-r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2*r, 2*r); - //g.fillArc(w / 2 - r, -r, 2*r, 2*r, 180, 180); - } else { - g.fillOval(w/2-r, Figure.SLOT_START - r, 2*r, 2*r); - //g.fillArc(w / 2 - r, h - r, 2*r, 2*r, 0, 180); + // Do not paint a slot with connections. } } } @@ -146,9 +146,9 @@ protected Rectangle calculateClientArea() { return new Rectangle(0, 0, slot.getWidth(), Figure.SLOT_WIDTH); } - + protected abstract int calculateSlotWidth(); - + protected int calculateWidth(int count) { return getFigureWidget().getFigure().getWidth() / count; } @@ -158,19 +158,19 @@ Set hiddenNodes = new HashSet<>(diagramScene.getModel().getHiddenNodes()); if (diagramScene.isAllVisible()) { hiddenNodes = new HashSet<>(diagramScene.getModel().getGraphToView().getGroup().getAllNodes()); - } + } boolean progress = false; - for(Figure f : diagramScene.getModel().getDiagramToView().getFigures()) { - for(Slot s : f.getSlots()) { - if(DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) { + for (Figure f : diagramScene.getModel().getDiagramToView().getFigures()) { + for (Slot s : f.getSlots()) { + if (DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) { progress = true; hiddenNodes.removeAll(f.getSource().getSourceNodesAsSet()); } } } - if(progress) { + if (progress) { this.diagramScene.getModel().showNot(hiddenNodes); } } diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/nbproject/platform.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Mon Mar 23 16:11:48 2015 +0100 @@ -1,114 +1,8 @@ +branding.token=idealgraphvisualizer cluster.path=\ ${nbplatform.active.dir}/ide:\ ${nbplatform.active.dir}/platform -disabled.modules=\ - org.apache.commons.codec,\ - org.apache.commons.httpclient,\ - org.apache.commons.io,\ - org.apache.commons.lang,\ - org.apache.ws.commons.util,\ - org.apache.xmlrpc,\ - org.eclipse.core.contenttype,\ - org.eclipse.core.jobs,\ - org.eclipse.core.net,\ - org.eclipse.core.runtime,\ - org.eclipse.core.runtime.compatibility.auth,\ - org.eclipse.equinox.app,\ - org.eclipse.equinox.common,\ - org.eclipse.equinox.preferences,\ - org.eclipse.equinox.registry,\ - org.eclipse.equinox.security,\ - org.eclipse.jgit,\ - org.eclipse.mylyn.bugzilla.core,\ - org.eclipse.mylyn.commons.core,\ - org.eclipse.mylyn.commons.net,\ - org.eclipse.mylyn.commons.repositories.core,\ - org.eclipse.mylyn.commons.xmlrpc,\ - org.eclipse.mylyn.tasks.core,\ - org.eclipse.mylyn.wikitext.confluence.core,\ - org.eclipse.mylyn.wikitext.core,\ - org.eclipse.mylyn.wikitext.textile.core,\ - org.netbeans.api.debugger,\ - org.netbeans.core.browser,\ - org.netbeans.core.browser.webview,\ - org.netbeans.libs.commons_net,\ - org.netbeans.libs.git,\ - org.netbeans.libs.ini4j,\ - org.netbeans.libs.jsch.agentproxy,\ - org.netbeans.libs.json_simple,\ - org.netbeans.libs.smack,\ - org.netbeans.libs.svnClientAdapter,\ - org.netbeans.libs.svnClientAdapter.javahl,\ - org.netbeans.libs.svnClientAdapter.svnkit,\ - org.netbeans.libs.swingx,\ - org.netbeans.modules.bugtracking,\ - org.netbeans.modules.bugtracking.bridge,\ - org.netbeans.modules.bugzilla,\ - org.netbeans.modules.code.analysis,\ - org.netbeans.modules.css.prep,\ - org.netbeans.modules.db,\ - org.netbeans.modules.db.core,\ - org.netbeans.modules.db.dataview,\ - org.netbeans.modules.db.drivers,\ - org.netbeans.modules.db.kit,\ - org.netbeans.modules.db.metadata.model,\ - org.netbeans.modules.db.mysql,\ - org.netbeans.modules.db.sql.editor,\ - org.netbeans.modules.db.sql.visualeditor,\ - org.netbeans.modules.dbapi,\ - org.netbeans.modules.derby,\ - org.netbeans.modules.editor.global.format,\ - org.netbeans.modules.editor.indent.project,\ - org.netbeans.modules.extexecution.impl,\ - org.netbeans.modules.git,\ - org.netbeans.modules.gototest,\ - org.netbeans.modules.gsf.codecoverage,\ - org.netbeans.modules.gsf.testrunner,\ - org.netbeans.modules.html.angular,\ - org.netbeans.modules.html.knockout,\ - org.netbeans.modules.hudson,\ - org.netbeans.modules.hudson.git,\ - org.netbeans.modules.hudson.mercurial,\ - org.netbeans.modules.hudson.subversion,\ - org.netbeans.modules.hudson.tasklist,\ - org.netbeans.modules.hudson.ui,\ - org.netbeans.modules.jellytools.ide,\ - org.netbeans.modules.languages,\ - org.netbeans.modules.lexer.nbbridge,\ - org.netbeans.modules.localhistory,\ - org.netbeans.modules.mercurial,\ - org.netbeans.modules.mylyn.util,\ - org.netbeans.modules.notifications,\ - org.netbeans.modules.parsing.ui,\ - org.netbeans.modules.project.ant,\ - org.netbeans.modules.projectui.buildmenu,\ - org.netbeans.modules.properties.syntax,\ - org.netbeans.modules.schema2beans,\ - org.netbeans.modules.server,\ - org.netbeans.modules.spellchecker,\ - org.netbeans.modules.spellchecker.apimodule,\ - org.netbeans.modules.spellchecker.bindings.htmlxml,\ - org.netbeans.modules.spellchecker.bindings.properties,\ - org.netbeans.modules.spellchecker.dictionary_en,\ - org.netbeans.modules.spellchecker.kit,\ - org.netbeans.modules.subversion,\ - org.netbeans.modules.swing.validation,\ - org.netbeans.modules.target.iterator,\ - org.netbeans.modules.team.commons,\ - org.netbeans.modules.team.ide,\ - org.netbeans.modules.utilities.project,\ - org.netbeans.modules.versioning,\ - org.netbeans.modules.versioning.core,\ - org.netbeans.modules.versioning.indexingbridge,\ - org.netbeans.modules.versioning.masterfs,\ - org.netbeans.modules.versioning.system.cvss.installer,\ - org.netbeans.modules.versioning.ui,\ - org.netbeans.modules.versioning.util,\ - org.netbeans.modules.web.webkit.debugging,\ - org.netbeans.modules.xml.multiview,\ - org.netbeans.spi.debugger.ui,\ - org.netbeans.spi.viewmodel,\ - org.openidex.util +disabled.modules= nbplatform.active.dir=${suite.dir}/nbplatform nbplatform.default.netbeans.dest.dir=${suite.dir}/nbplatform nbplatform.default.harness.dir=${nbplatform.default.netbeans.dest.dir}/harness diff -r 422e60a2f4b9 -r 220c494e5088 src/share/tools/IdealGraphVisualizer/nbproject/project.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Mon Mar 23 16:11:48 2015 +0100 @@ -1,44 +1,50 @@ -app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif -app.name=idealgraphvisualizer -app.title=IdealGraphVisualizer -branding.token=${app.name} -modules=\ - ${project.com.sun.hotspot.igv.graph}:\ - ${project.com.sun.hotspot.igv.coordinator}:\ - ${project.com.sun.hotspot.igv.filter}:\ - ${project.com.sun.hotspot.igv.hierarchicallayout}:\ - ${project.com.sun.hotspot.igv.layout}:\ - ${project.com.sun.hotspot.igv.data}:\ - ${project.com.sun.hotspot.igv.view}:\ - ${project.com.sun.hotspot.igv.bytecodes}:\ - ${project.com.sun.hotspot.igv.difference}:\ - ${project.com.sun.hotspot.igv.settings}:\ - ${project.com.sun.hotspot.igv.util}:\ - ${project.com.sun.hotspot.igv.svg}:\ - ${project.com.sun.hotspot.connection}:\ - ${project.com.sun.hotspot.igv.servercompilerscheduler}:\ - ${project.com.sun.hotspot.igv.filterwindow}:\ - ${project.com.sun.hotspot.igv.selectioncoordinator}:\ - ${project.com.sun.hotspot.igv.graal} -project.com.sun.hotspot.connection=NetworkConnection -project.com.sun.hotspot.igv.bytecodes=Bytecodes -project.com.sun.hotspot.igv.coordinator=Coordinator -project.com.sun.hotspot.igv.data=Data -project.com.sun.hotspot.igv.difference=Difference -project.com.sun.hotspot.igv.filter=Filter -project.com.sun.hotspot.igv.filterwindow=FilterWindow -project.com.sun.hotspot.igv.graal=Graal -project.com.sun.hotspot.igv.graph=Graph -project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout -project.com.sun.hotspot.igv.layout=Layout -project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator -project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler -project.com.sun.hotspot.igv.settings=Settings -project.com.sun.hotspot.igv.svg=BatikSVGProxy -project.com.sun.hotspot.igv.view=View -project.com.sun.hotspot.igv.util=Util - -# Disable assertions for RequestProcessor to prevent annoying messages in case -# of multiple SceneAnimator update tasks in the default RequestProcessor. -run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000 -debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor +app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif +app.name=${branding.token} +app.title=IdealGraphVisualizer +auxiliary.org-netbeans-modules-apisupport-installer.license-type=no +auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false +auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=true +auxiliary.org-netbeans-modules-apisupport-installer.os-solaris=false +auxiliary.org-netbeans-modules-apisupport-installer.os-windows=false +auxiliary.org-netbeans-modules-apisupport-installer.pack200-enabled=false +auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml +modules=\ + ${project.com.sun.hotspot.igv.graph}:\ + ${project.com.sun.hotspot.igv.coordinator}:\ + ${project.com.sun.hotspot.igv.filter}:\ + ${project.com.sun.hotspot.igv.hierarchicallayout}:\ + ${project.com.sun.hotspot.igv.layout}:\ + ${project.com.sun.hotspot.igv.data}:\ + ${project.com.sun.hotspot.igv.view}:\ + ${project.com.sun.hotspot.igv.bytecodes}:\ + ${project.com.sun.hotspot.igv.difference}:\ + ${project.com.sun.hotspot.igv.settings}:\ + ${project.com.sun.hotspot.igv.util}:\ + ${project.com.sun.hotspot.igv.svg}:\ + ${project.com.sun.hotspot.connection}:\ + ${project.com.sun.hotspot.igv.servercompilerscheduler}:\ + ${project.com.sun.hotspot.igv.filterwindow}:\ + ${project.com.sun.hotspot.igv.selectioncoordinator}:\ + ${project.com.sun.hotspot.igv.graal} +project.com.sun.hotspot.connection=NetworkConnection +project.com.sun.hotspot.igv.bytecodes=Bytecodes +project.com.sun.hotspot.igv.coordinator=Coordinator +project.com.sun.hotspot.igv.data=Data +project.com.sun.hotspot.igv.difference=Difference +project.com.sun.hotspot.igv.filter=Filter +project.com.sun.hotspot.igv.filterwindow=FilterWindow +project.com.sun.hotspot.igv.graal=Graal +project.com.sun.hotspot.igv.graph=Graph +project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout +project.com.sun.hotspot.igv.layout=Layout +project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator +project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler +project.com.sun.hotspot.igv.settings=Settings +project.com.sun.hotspot.igv.svg=BatikSVGProxy +project.com.sun.hotspot.igv.view=View +project.com.sun.hotspot.igv.util=Util + +# Disable assertions for RequestProcessor to prevent annoying messages in case +# of multiple SceneAnimator update tasks in the default RequestProcessor. +run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000 +debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor diff -r 422e60a2f4b9 -r 220c494e5088 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon Mar 23 15:58:36 2015 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Mar 23 16:11:48 2015 +0100 @@ -1547,6 +1547,7 @@ if (TraceDeoptimization) { // make noise on the tty tty->print("Uncommon trap occurred in"); nm->method()->print_short_name(tty); + tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id()); #ifdef GRAAL oop installedCode = nm->graal_installed_code(); if (installedCode != NULL) {