changeset 12609:b81405d42861

Merge
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Fri, 25 Oct 2013 19:24:11 +0200
parents a2340324fc79 (current diff) 7328f7def427 (diff)
children 62fb4919edc9
files
diffstat 9 files changed, 317 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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:
--- 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;
 
--- 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;
     }
 }
--- 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<InstalledCode> 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<InstalledCode> 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);
--- 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());
                 }
--- 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<InstalledCode> compile(OptimizedCallTarget node);
 }
--- 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<Runnable>());
+
         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<InstalledCode>() {
+    public Future<InstalledCode> compile(final OptimizedCallTarget compilable) {
+        Future<InstalledCode> future = compileQueue.submit(new Callable<InstalledCode>() {
 
             @Override
             public InstalledCode call() throws Exception {
-                return compileMethodImpl(compilable);
+                Object[] debug = new Object[]{new DebugDumpScope("Truffle: " + compilable)};
+                return Debug.scope("Truffle", debug, new Callable<InstalledCode>() {
+
+                    @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<InstalledCode>() {
-            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;
     }
 
--- 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<Boolean> TruffleUseTimeForCompilationDecision = new OptionValue<>(false);
     @Option(help = "")
-    public static final OptionValue<Long> TruffleCompilationDecisionTime = new OptionValue<>(100 * 1000000L);
+    public static final OptionValue<Integer> TruffleCompilationDecisionTime = new OptionValue<>(100);
     @Option(help = "")
     public static final OptionValue<Boolean> TruffleCompilationDecisionTimePrintFail = new OptionValue<>(false);
     @Option(help = "")
@@ -90,6 +90,8 @@
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleInlining = new OptionValue<>(true);
     @Option(help = "")
+    public static final OptionValue<Boolean> TraceTruffleInliningTree = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleInliningDetails = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TruffleCallTargetProfiling = new StableOptionValue<>(false);