# HG changeset patch # User Christos Kotselidis # Date 1382721851 -7200 # Node ID b81405d42861dfba8edca6cd347511839d3ba7a4 # Parent a2340324fc7951defce560add6eae30d497214ae# Parent 7328f7def427a2f04b8708cedfe5bd704a4ef0a4 Merge diff -r a2340324fc79 -r b81405d42861 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 Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Fri Oct 25 19:24:11 2013 +0200 @@ -690,19 +690,33 @@ Variable input = load(inputVal); Variable result = newVariable(opcode.to); switch (opcode) { + case B2L: + case S2L: + case C2L: + // x2L == x2I . I2L + // since byte, short and char are stored as int in registers, x2I is a nop case I2L: append(new Unary2Op(I2L, result, input)); break; case L2I: append(new Unary1Op(L2I, result, input)); break; + case C2B: + case S2B: case I2B: + case L2B: append(new Unary2Op(I2B, result, input)); break; + case B2C: + case S2C: case I2C: + case L2C: append(new Unary1Op(I2C, result, input)); break; + case B2S: + case C2S: case I2S: + case L2S: append(new Unary2Op(I2S, result, input)); break; case F2D: @@ -751,6 +765,9 @@ // Instructions that move or generate 32-bit register values also set the upper 32 // bits of the register to zero. // Consequently, there is no need for a special zero-extension move. + case B2I: + case C2I: + case S2I: emitMove(result, input); break; default: diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Fri Oct 25 19:24:11 2013 +0200 @@ -37,11 +37,27 @@ public class ConvertNode extends FloatingNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable { public static enum Op { + // formatter:off + B2S(Byte, Short, true), + B2C(Byte, Char, true), + B2I(Byte, Int, true), + B2L(Byte, Long, true), + S2B(Short, Byte, false), + S2C(Short, Char, true), + S2I(Short, Int, true), + S2L(Short, Long, true), + C2B(Char, Byte, false), + C2S(Char, Short, true), + C2I(Char, Int, true), + C2L(Char, Long, true), I2L(Int, Long, true), L2I(Long, Int, false), I2B(Int, Byte, false), I2C(Int, Char, false), I2S(Int, Short, false), + L2B(Long, Byte, false), + L2C(Long, Char, false), + L2S(Long, Short, false), F2D(Float, Double, true), D2F(Double, Float, false), I2F(Int, Float, false), @@ -57,6 +73,7 @@ MOV_L2D(Long, Double, false), MOV_F2I(Float, Int, false), MOV_D2L(Double, Long, false); + // formatter:on public final Kind from; public final Kind to; @@ -74,6 +91,45 @@ public static Op getOp(Kind from, Kind to) { switch (from) { + case Byte: + switch (to) { + case Char: + return B2C; + case Short: + return B2S; + case Int: + return B2I; + case Long: + return B2L; + default: + throw GraalInternalError.shouldNotReachHere(); + } + case Char: + switch (to) { + case Byte: + return C2B; + case Short: + return C2S; + case Int: + return C2I; + case Long: + return C2L; + default: + throw GraalInternalError.shouldNotReachHere(); + } + case Short: + switch (to) { + case Byte: + return S2B; + case Char: + return S2C; + case Int: + return S2I; + case Long: + return S2L; + default: + throw GraalInternalError.shouldNotReachHere(); + } case Int: switch (to) { case Byte: @@ -93,6 +149,12 @@ } case Long: switch (to) { + case Byte: + return L2B; + case Char: + return L2C; + case Short: + return L2S; case Int: return L2I; case Float: @@ -146,7 +208,7 @@ */ public ConvertNode(Op opcode, ValueNode value) { super(StampFactory.forKind(opcode.to.getStackKind())); - assert value.kind() == opcode.from : opcode + " : " + value.kind() + " != " + opcode.from; + assert value.kind() == opcode.from.getStackKind() : opcode + " : " + value.kind() + " != " + opcode.from; this.opcode = opcode; this.value = value; } @@ -155,6 +217,30 @@ assert inputs.length == 1; Constant c = inputs[0]; switch (opcode) { + case B2C: + return Constant.forChar((char) (byte) c.asInt()); + case B2S: + return Constant.forShort((byte) c.asInt()); + case B2I: + return Constant.forInt((byte) c.asInt()); + case B2L: + return Constant.forLong((byte) c.asInt()); + case C2B: + return Constant.forByte((byte) (char) c.asInt()); + case C2S: + return Constant.forShort((short) (char) c.asInt()); + case C2I: + return Constant.forInt((char) c.asInt()); + case C2L: + return Constant.forLong((char) c.asInt()); + case S2B: + return Constant.forByte((byte) (short) c.asInt()); + case S2C: + return Constant.forChar((char) (short) c.asInt()); + case S2I: + return Constant.forInt((short) c.asInt()); + case S2L: + return Constant.forLong((short) c.asInt()); case I2L: return Constant.forLong(c.asInt()); case L2I: @@ -165,6 +251,12 @@ return Constant.forChar((char) c.asInt()); case I2S: return Constant.forShort((short) c.asInt()); + case L2B: + return Constant.forByte((byte) c.asLong()); + case L2C: + return Constant.forChar((char) c.asLong()); + case L2S: + return Constant.forShort((short) c.asLong()); case F2D: return Constant.forDouble(c.asFloat()); case D2F: diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java --- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java Fri Oct 25 19:24:11 2013 +0200 @@ -45,7 +45,7 @@ public static int getCompiledMethodFieldOffset() { if (compiledMethodFieldOffset == -1) { - compiledMethodFieldOffset = getFieldOffset("compiledMethod", OptimizedCallTarget.class); + compiledMethodFieldOffset = getFieldOffset("installedCode", OptimizedCallTarget.class); } return compiledMethodFieldOffset; diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Fri Oct 25 19:24:11 2013 +0200 @@ -84,8 +84,20 @@ return getObjectUnsafe(slot); } + private Object[] getLocals() { + return CompilerDirectives.unsafeCast(locals, Object[].class, true); + } + + private long[] getPrimitiveLocals() { + return CompilerDirectives.unsafeCast(this.primitiveLocals, long[].class, true); + } + + private byte[] getTags() { + return CompilerDirectives.unsafeCast(tags, byte[].class, true); + } + private Object getObjectUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetObject(locals, (long) slot.getIndex() * Unsafe.ARRAY_OBJECT_INDEX_SCALE + Unsafe.ARRAY_OBJECT_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetObject(getLocals(), (long) slot.getIndex() * Unsafe.ARRAY_OBJECT_INDEX_SCALE + Unsafe.ARRAY_OBJECT_BASE_OFFSET, true, slot); } @Override @@ -95,7 +107,7 @@ } private void setObjectUnsafe(FrameSlot slot, Object value) { - CompilerDirectives.unsafePutObject(locals, (long) slot.getIndex() * Unsafe.ARRAY_OBJECT_INDEX_SCALE + Unsafe.ARRAY_OBJECT_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutObject(getLocals(), (long) slot.getIndex() * Unsafe.ARRAY_OBJECT_INDEX_SCALE + Unsafe.ARRAY_OBJECT_BASE_OFFSET, value, slot); } @Override @@ -105,7 +117,7 @@ } private byte getByteUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetByte(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetByte(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -115,7 +127,7 @@ } private void setByteUnsafe(FrameSlot slot, byte value) { - CompilerDirectives.unsafePutByte(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutByte(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -125,7 +137,7 @@ } private boolean getBooleanUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetBoolean(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetBoolean(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -135,7 +147,7 @@ } private void setBooleanUnsafe(FrameSlot slot, boolean value) { - CompilerDirectives.unsafePutBoolean(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutBoolean(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -145,7 +157,7 @@ } private float getFloatUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetFloat(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetFloat(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -155,7 +167,7 @@ } private void setFloatUnsafe(FrameSlot slot, float value) { - CompilerDirectives.unsafePutFloat(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutFloat(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -165,7 +177,7 @@ } private long getLongUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetLong(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetLong(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -175,7 +187,7 @@ } private void setLongUnsafe(FrameSlot slot, long value) { - CompilerDirectives.unsafePutLong(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutLong(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -185,7 +197,7 @@ } private int getIntUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetInt(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetInt(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -195,7 +207,7 @@ } private void setIntUnsafe(FrameSlot slot, int value) { - CompilerDirectives.unsafePutInt(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutInt(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -205,7 +217,7 @@ } private double getDoubleUnsafe(FrameSlot slot) { - return CompilerDirectives.unsafeGetDouble(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); + return CompilerDirectives.unsafeGetDouble(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, true, slot); } @Override @@ -215,7 +227,7 @@ } private void setDoubleUnsafe(FrameSlot slot, double value) { - CompilerDirectives.unsafePutDouble(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); + CompilerDirectives.unsafePutDouble(getPrimitiveLocals(), (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value, slot); } @Override @@ -225,25 +237,25 @@ private void verifySet(FrameSlot slot, FrameSlotKind accessKind) { int slotIndex = slot.getIndex(); - if (slotIndex >= tags.length) { + if (slotIndex >= getTags().length) { CompilerDirectives.transferToInterpreter(); resize(); } - tags[slotIndex] = (byte) accessKind.ordinal(); + getTags()[slotIndex] = (byte) accessKind.ordinal(); } private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException { int slotIndex = slot.getIndex(); - if (slotIndex >= tags.length) { + if (slotIndex >= getTags().length) { CompilerDirectives.transferToInterpreter(); resize(); } - byte tag = this.tags[slotIndex]; + byte tag = this.getTags()[slotIndex]; if (accessKind == FrameSlotKind.Object ? tag != 0 : tag != accessKind.ordinal()) { CompilerDirectives.transferToInterpreter(); if (slot.getKind() == accessKind || tag == 0) { descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot)); - if (tags[slotIndex] == accessKind.ordinal()) { + if (getTags()[slotIndex] == accessKind.ordinal()) { return; } } @@ -254,11 +266,11 @@ @Override public Object getValue(FrameSlot slot) { int slotIndex = slot.getIndex(); - if (slotIndex >= tags.length) { + if (slotIndex >= getTags().length) { CompilerDirectives.transferToInterpreter(); resize(); } - byte tag = tags[slotIndex]; + byte tag = getTags()[slotIndex]; if (tag == FrameSlotKind.Boolean.ordinal()) { return getBooleanUnsafe(slot); } else if (tag == FrameSlotKind.Byte.ordinal()) { @@ -291,10 +303,10 @@ @Override public boolean isInitialized(FrameSlot slot) { int slotIndex = slot.getIndex(); - if (slotIndex >= tags.length) { + if (slotIndex >= getTags().length) { CompilerDirectives.transferToInterpreter(); resize(); } - return tags[slotIndex] != 0; + return getTags()[slotIndex] != 0; } } diff -r a2340324fc79 -r b81405d42861 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 Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Oct 25 19:24:11 2013 +0200 @@ -26,6 +26,7 @@ import java.io.*; import java.util.*; +import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; @@ -53,21 +54,22 @@ } } - private InstalledCode compiledMethod; + private InstalledCode installedCode; + private Future installedCodeTask; private final TruffleCompiler compiler; private final CompilationPolicy compilationPolicy; + private boolean disableCompilation; + private int callCount; - private boolean disableCompilation; - - private int callCount; + /** + * Number of times an installed code for this tree was invalidated. + */ private int invalidationCount; - private int replaceCount; - long timeCompilationStarted; - long timePartialEvaluationFinished; - long timeCompilationFinished; - int codeSize; - int nodeCountPartialEval; - int nodeCountLowered; + + /** + * Number of times a node was replaced in this tree. + */ + private int nodeReplaceCount; @Override public Object call(PackedFrame caller, Arguments args) { @@ -75,7 +77,7 @@ } private Object callHelper(PackedFrame caller, Arguments args) { - if (compiledMethod != null && compiledMethod.isValid()) { + if (installedCode != null && installedCode.isValid()) { TruffleRuntime runtime = Truffle.getRuntime(); if (runtime instanceof GraalTruffleRuntime) { OUT.printf("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); @@ -86,9 +88,9 @@ if (TruffleCallTargetProfiling.getValue()) { callCount++; } - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) { try { - return compiledMethod.execute(this, caller, args); + return installedCode.execute(this, caller, args); } catch (InvalidInstalledCodeException ex) { return compiledCodeInvalidated(caller, args); } @@ -98,15 +100,28 @@ } private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { - CompilerAsserts.neverPartOfCompilation(); - compiledMethod = null; - invalidationCount++; - compilationPolicy.compilationInvalidated(); - if (TraceTruffleCompilation.getValue()) { - OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms |Inv# %d |Replace# %d\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6, - invalidationCount, replaceCount); + invalidate(); + return call(caller, args); + } + + private void invalidate() { + InstalledCode m = this.installedCode; + if (m != null) { + CompilerAsserts.neverPartOfCompilation(); + installedCode = null; + invalidationCount++; + compilationPolicy.compilationInvalidated(); + if (TraceTruffleCompilation.getValue()) { + OUT.printf("[truffle] invalidated %-48s |Inv# %d |Replace# %d\n", rootNode, invalidationCount, nodeReplaceCount); + } } - return call(caller, args); + + Future task = this.installedCodeTask; + if (task != null) { + task.cancel(true); + this.installedCodeTask = null; + compilationPolicy.compilationInvalidated(); + } } private Object interpreterCall(PackedFrame caller, Arguments args) { @@ -115,19 +130,55 @@ if (disableCompilation || !compilationPolicy.compileOrInline()) { return executeHelper(caller, args); } else { - compileOrInline(); - return call(caller, args); + return compileOrInline(caller, args); } } - private void compileOrInline() { + private Object compileOrInline(PackedFrame caller, Arguments args) { + if (installedCodeTask != null) { + // There is already a compilation running. + if (installedCodeTask.isCancelled()) { + installedCodeTask = null; + } else { + if (installedCodeTask.isDone()) { + receiveInstalledCode(); + } + return executeHelper(caller, args); + } + } + if (TruffleFunctionInlining.getValue() && inline()) { compilationPolicy.inlined(MIN_INVOKES_AFTER_INLINING); + return call(caller, args); } else { compile(); + return executeHelper(caller, args); } } + private void receiveInstalledCode() { + try { + this.installedCode = installedCodeTask.get(); + if (TruffleCallTargetProfiling.getValue()) { + resetProfiling(); + } + } catch (InterruptedException | ExecutionException e) { + disableCompilation = true; + OUT.printf("[truffle] opt failed %-48s %s\n", rootNode, e.getMessage()); + if (e.getCause() instanceof BailoutException) { + // Bailout => move on. + } else { + if (TraceTruffleCompilationExceptions.getValue()) { + e.printStackTrace(OUT); + } + if (TruffleCompilationExceptionsAreFatal.getValue()) { + System.exit(-1); + } + } + } + installedCodeTask = null; + } + public boolean inline() { CompilerAsserts.neverPartOfCompilation(); return new InliningHelper(this).inline(); @@ -135,36 +186,9 @@ public void compile() { CompilerAsserts.neverPartOfCompilation(); - try { - compiledMethod = compiler.compile(this); - if (compiledMethod == null) { - throw new BailoutException(String.format("code installation failed (codeSize=%s)", codeSize)); - } else { - if (TraceTruffleCompilation.getValue()) { - int nodeCountTruffle = NodeUtil.countNodes(rootNode); - OUT.printf("[truffle] optimized %-50s |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", rootNode, nodeCountTruffle, - (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, - (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); - } - if (TruffleCallTargetProfiling.getValue()) { - resetProfiling(); - } - } - } catch (Throwable e) { - disableCompilation = true; - if (TraceTruffleCompilation.getValue()) { - if (e instanceof BailoutException) { - OUT.printf("[truffle] opt bailout %-48s %s\n", rootNode, e.getMessage()); - } else { - OUT.printf("[truffle] opt failed %-49s %s\n", rootNode, e.toString()); - if (TraceTruffleCompilationExceptions.getValue()) { - e.printStackTrace(OUT); - } - if (TruffleCompilationExceptionsAreFatal.getValue()) { - System.exit(-1); - } - } - } + this.installedCodeTask = compiler.compile(this); + if (!TruffleBackgroundCompilation.getValue()) { + receiveInstalledCode(); } } @@ -189,13 +213,8 @@ @Override public void nodeReplaced() { - replaceCount++; - if (compiledMethod != null) { - if (compiledMethod.isValid()) { - compiledMethod.invalidate(); - } - compiledMethod = null; - } + nodeReplaceCount++; + invalidate(); compilationPolicy.nodeReplaced(); } @@ -409,7 +428,7 @@ int notInlinedCallSiteCount = InliningHelper.getInlinableCallSites(callTarget).size(); int nodeCount = NodeUtil.countNodes(callTarget.rootNode); int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.rootNode, InlinedCallSite.class); - String comment = callTarget.compiledMethod == null ? " int" : ""; + String comment = callTarget.installedCode == null ? " int" : ""; comment += callTarget.disableCompilation ? " fail" : ""; OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, callTarget.invalidationCount, comment); diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Oct 25 19:24:11 2013 +0200 @@ -131,6 +131,10 @@ // Make sure frame does not escape. expandTree(graph, assumptions); + if (Thread.interrupted()) { + return; + } + new VerifyFrameDoesNotEscapePhase().apply(graph, false); if (TraceTruffleCompilationDetails.getValue() && constantReceivers != null) { @@ -218,6 +222,10 @@ } } + if (Thread.interrupted()) { + return; + } + if (graph.getNodeCount() > TruffleCompilerOptions.TruffleGraphMaxNodes.getValue()) { throw new BailoutException("Truffle compilation is exceeding maximum node count: " + graph.getNodeCount()); } diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Fri Oct 25 19:24:11 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.truffle; +import java.util.concurrent.*; + import com.oracle.graal.api.code.*; /** @@ -30,5 +32,5 @@ */ public interface TruffleCompiler { - InstalledCode compile(OptimizedCallTarget node); + Future compile(OptimizedCallTarget node); } diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Oct 25 19:24:11 2013 +0200 @@ -23,7 +23,9 @@ package com.oracle.graal.truffle; import static com.oracle.graal.api.code.CodeUtil.*; +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; +import java.io.*; import java.util.*; import java.util.concurrent.*; @@ -54,6 +56,8 @@ */ public class TruffleCompilerImpl implements TruffleCompiler { + private static final PrintStream OUT = TTY.out().out(); + private final Providers providers; private final Suites suites; private final PartialEvaluator partialEvaluator; @@ -61,6 +65,7 @@ private final ResolvedJavaType[] skippedExceptionTypes; private final RuntimeProvider runtime; private final TruffleCache truffleCache; + private final ThreadPoolExecutor compileQueue; private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; @@ -75,6 +80,9 @@ this.suites = backend.getSuites().createSuites(); this.skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); + // Create compilation queue. + compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); + final GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(); config.setSkippedExceptionTypes(skippedExceptionTypes); this.truffleCache = new TruffleCache(providers, config, TruffleCompilerImpl.Optimizations); @@ -94,15 +102,22 @@ return skippedExceptionTypes; } - public InstalledCode compile(final OptimizedCallTarget compilable) { - Object[] debug = new Object[]{new TruffleDebugJavaMethod(compilable)}; - return Debug.scope("Truffle", debug, new Callable() { + public Future compile(final OptimizedCallTarget compilable) { + Future future = compileQueue.submit(new Callable() { @Override public InstalledCode call() throws Exception { - return compileMethodImpl(compilable); + Object[] debug = new Object[]{new DebugDumpScope("Truffle: " + compilable)}; + return Debug.scope("Truffle", debug, new Callable() { + + @Override + public InstalledCode call() throws Exception { + return compileMethodImpl(compilable); + } + }); } }); + return future; } public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime"); @@ -118,28 +133,69 @@ graphCache.removeStaleGraphs(); } - compilable.timeCompilationStarted = System.nanoTime(); + if (TraceTruffleInliningTree.getValue()) { + printInlineTree(compilable.getRootNode()); + } + + long timeCompilationStarted = System.nanoTime(); Assumptions assumptions = new Assumptions(true); try (TimerCloseable a = PartialEvaluationTime.start()) { graph = partialEvaluator.createGraph(compilable, assumptions); } - compilable.timePartialEvaluationFinished = System.nanoTime(); - compilable.nodeCountPartialEval = graph.getNodeCount(); - InstalledCode compiledMethod = compileMethodHelper(graph, config, compilable, assumptions); - compilable.timeCompilationFinished = System.nanoTime(); - compilable.nodeCountLowered = graph.getNodeCount(); + if (Thread.interrupted()) { + return null; + } + long timePartialEvaluationFinished = System.nanoTime(); + int nodeCountPartialEval = graph.getNodeCount(); + InstalledCode compiledMethod = compileMethodHelper(graph, config, assumptions); + long timeCompilationFinished = System.nanoTime(); + int nodeCountLowered = graph.getNodeCount(); + + if (compiledMethod == null) { + throw new BailoutException("Could not install method, code cache is full!"); + } + + if (TraceTruffleCompilation.getValue()) { + int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode()); + OUT.printf("[truffle] optimized %-50s %d |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, + (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, + (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, compiledMethod.getCode().length); + } return compiledMethod; } + private void printInlineTree(RootNode rootNode) { + OUT.println(); + OUT.println("Inlining tree for: " + rootNode); + rootNode.accept(new InlineTreeVisitor()); + } + + private class InlineTreeVisitor implements NodeVisitor { + + public boolean visit(Node node) { + if (node instanceof InlinedCallSite) { + InlinedCallSite inlinedCallSite = (InlinedCallSite) node; + int indent = this.indent(node); + for (int i = 0; i < indent; ++i) { + OUT.print(" "); + } + OUT.println(inlinedCallSite.getCallTarget()); + } + return true; + } + + private int indent(Node n) { + if (n instanceof RootNode) { + return 0; + } else if (n instanceof InlinedCallSite) { + return indent(n.getParent()) + 1; + } else { + return indent(n.getParent()); + } + } + } + public InstalledCode compileMethodHelper(final StructuredGraph graph, final GraphBuilderConfiguration config, final Assumptions assumptions) { - return Debug.scope("Truffle", graph, new Callable() { - public InstalledCode call() throws Exception { - return compileMethodHelper(graph, config, null, assumptions); - } - }); - } - - public InstalledCode compileMethodHelper(final StructuredGraph graph, final GraphBuilderConfiguration config, final OptimizedCallTarget compilable, final Assumptions assumptions) { final PhasePlan plan = createPhasePlan(config); Debug.scope("TruffleFinal", new Runnable() { @@ -159,7 +215,7 @@ public CompilationResult call() { CodeCacheProvider codeCache = providers.getCodeCache(); CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); - CompilationResult compilationResult = new CompilationResult(compilable.toString()); + CompilationResult compilationResult = new CompilationResult(graph.method().toString()); return GraalCompiler.compileGraphNoScope(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, plan, OptimisticOptimizations.ALL, new SpeculationLog(), suites, compilationResult); } @@ -205,9 +261,6 @@ if (Debug.isLogEnabled()) { Debug.log(providers.getCodeCache().disassemble(result, compiledMethod)); } - if (compilable != null) { - compilable.codeSize = result.getTargetCodeSize(); - } return compiledMethod; } diff -r a2340324fc79 -r b81405d42861 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Fri Oct 25 19:23:38 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Fri Oct 25 19:24:11 2013 +0200 @@ -70,7 +70,7 @@ @Option(help = "") public static final OptionValue TruffleUseTimeForCompilationDecision = new OptionValue<>(false); @Option(help = "") - public static final OptionValue TruffleCompilationDecisionTime = new OptionValue<>(100 * 1000000L); + public static final OptionValue TruffleCompilationDecisionTime = new OptionValue<>(100); @Option(help = "") public static final OptionValue TruffleCompilationDecisionTimePrintFail = new OptionValue<>(false); @Option(help = "") @@ -90,6 +90,8 @@ @Option(help = "") public static final OptionValue TraceTruffleInlining = new OptionValue<>(true); @Option(help = "") + public static final OptionValue TraceTruffleInliningTree = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TraceTruffleInliningDetails = new OptionValue<>(false); @Option(help = "") public static final OptionValue TruffleCallTargetProfiling = new StableOptionValue<>(false);