changeset 15526:5ecbed00da23

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 02 May 2014 02:45:26 +0200
parents b3fbf52f34be (current diff) a20be10ad437 (diff)
children ff5cacf47b68
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java
diffstat 94 files changed, 2567 insertions(+), 1543 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterSaveLayout.java	Fri May 02 02:45:26 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,16 +33,16 @@
     /**
      * Keys.
      */
-    private Register[] registers;
+    private final Register[] registers;
 
     /**
      * Slot indexes relative to stack pointer.
      */
-    private int[] slots;
+    private final int[] slots;
 
     /**
      * Creates a map from registers to frame slots.
-     * 
+     *
      * @param registers the keys in the map
      * @param slots frame slot index for each register in {@code registers}
      */
@@ -55,6 +55,21 @@
     }
 
     /**
+     * Gets the frame slot index for a given register.
+     *
+     * @param register register to get the frame slot index for
+     * @return frame slot index
+     */
+    public int registerToSlot(Register register) {
+        for (int i = 0; i < registers.length; i++) {
+            if (register.equals(registers[i])) {
+                return slots[i];
+            }
+        }
+        throw new IllegalArgumentException(register + " not saved by this layout: " + this);
+    }
+
+    /**
      * Gets this layout information as a {@link Map} from registers to slots.
      */
     public Map<Register, Integer> registersToSlots(boolean sorted) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java	Fri May 02 02:45:26 2014 +0200
@@ -40,24 +40,6 @@
         }
     };
 
-    /**
-     * This is the Value of a node which was matched as part of a complex match. The value isn't
-     * actually useable but this marks it as having been evaluated.
-     */
-    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
-
-        @Override
-        public String toString() {
-            return "INTERIOR_MATCH";
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            // This class is a singleton
-            return other != null && getClass() == other.getClass();
-        }
-    };
-
     private final Kind kind;
     private final PlatformKind platformKind;
 
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri May 02 02:45:26 2014 +0200
@@ -79,6 +79,14 @@
         }
     }
 
+    public final void movptr(Register dst, AMD64Address src) {
+        movq(dst, src);
+    }
+
+    public final void movptr(AMD64Address dst, Register src) {
+        movq(dst, src);
+    }
+
     public final void movptr(AMD64Address dst, int src) {
         movslq(dst, src);
     }
@@ -277,7 +285,7 @@
     /**
      * Emit code to save a given set of callee save registers in the {@linkplain CalleeSaveLayout
      * CSA} within the frame.
-     * 
+     *
      * @param csl the description of the CSA
      * @param frameToCSA offset from the frame pointer to the CSA
      */
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri May 02 02:45:26 2014 +0200
@@ -182,20 +182,16 @@
                 // Only imm32 as long
                 return null;
             }
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
-                    gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-                    return null;
-                }
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
             };
         } else {
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
-                    gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-                    return null;
-                }
+            return builder -> {
+                gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
             };
         }
     }
@@ -320,8 +316,6 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
-    static Object lock = new Object();
-
     private AMD64Arithmetic getOp(ValueNode operation, Access access) {
         Kind memoryKind = getMemoryKind(access);
         if (operation.getClass() == IntegerAddNode.class) {
@@ -391,17 +385,10 @@
         return null;
     }
 
-    @MatchRule("(If (IntegerTest=compare Read=access value))")
-    @MatchRule("(If (IntegerTest=compare FloatingRead=access value))")
-    public static class IfIntegerTest extends AMD64MatchGenerator {
-        IfNode root;
-        Access access;
-        ValueNode value;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return gen.emitIntegerTestBranchMemory(root, value, access);
-        }
+    @MatchRule("(If (IntegerTest Read=access value))")
+    @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
+        return emitIntegerTestBranchMemory(root, value, access);
     }
 
     @MatchRule("(If (IntegerEquals=compare value Read=access))")
@@ -414,62 +401,32 @@
     @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
     @MatchRule("(If (FloatLessThan=compare value Read=access))")
     @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
-    public static class IfCompareMemory extends AMD64MatchGenerator {
-        IfNode root;
-        Access access;
-        ValueNode value;
-        CompareNode compare;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return gen.emitCompareBranchMemory(root, compare, value, access);
-        }
+    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        return emitCompareBranchMemory(root, compare, value, access);
     }
 
     @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
-    public static class RotateLeftConstant extends AMD64MatchGenerator {
-        LeftShiftNode lshift;
-        UnsignedRightShiftNode rshift;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
-                return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(lshift.x()), gen.operand(lshift.y()));
-            }
-            return null;
+    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
+        if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y()));
         }
-
+        return null;
     }
 
-    @MatchRule("(Or (LeftShift=lshift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
-    public static class RotateRightVariable extends AMD64MatchGenerator {
-        ValueNode value;
-        ValueNode shiftAmount;
-        ConstantNode delta;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
-                return builder -> gen.getLIRGeneratorTool().emitRor(gen.operand(value), gen.operand(shiftAmount));
-            }
-            return null;
+    @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
         }
-
+        return null;
     }
 
     @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))")
-    public static class RotateLeftVariable extends AMD64MatchGenerator {
-        ValueNode value;
-        ValueNode shiftAmount;
-        ConstantNode delta;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
-                return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(value), gen.operand(shiftAmount));
-            }
-            return null;
+    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
+        if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
         }
+        return null;
     }
 
     @MatchRule("(IntegerAdd value Read=access)")
@@ -490,121 +447,61 @@
     @MatchRule("(Or value FloatingRead=access)")
     @MatchRule("(Xor value FloatingRead=access)")
     @MatchRule("(And value FloatingRead=access)")
-    public static class BinaryRead extends AMD64MatchGenerator {
-        BinaryNode root;
-        Access access;
-        ValueNode value;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            AMD64Arithmetic op = gen.getOp(root, access);
-            if (op != null) {
-                return builder -> gen.getLIRGeneratorTool().emitBinaryMemory(op, gen.getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(value)), gen.makeAddress(access),
-                                gen.getState(access));
-            }
-            return null;
+    public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) {
+        AMD64Arithmetic op = getOp(root, access);
+        if (op != null) {
+            return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access));
         }
+        return null;
     }
 
     @MatchRule("(Write Narrow=narrow value)")
-    public static class WriteNarrow extends AMD64MatchGenerator {
-        WriteNode root;
-        NarrowNode narrow;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return new ComplexMatchResult() {
-                @Override
-                public Value evaluate(NodeLIRBuilder builder) {
-                    PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(root.value().stamp());
-                    Value address = root.location().generateAddress(builder, gen.getLIRGeneratorTool(), gen.operand(root.object()));
-                    Value v = gen.operand(narrow.getInput());
-                    gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(root));
-                    return null;
-                }
-            };
-        }
+    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
+        return builder -> {
+            PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
+            Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object()));
+            Value v = operand(narrow.getInput());
+            getLIRGeneratorTool().emitStore(writeKind, address, v, state(root));
+            return null;
+        };
     }
 
     @MatchRule("(SignExtend Read=access)")
     @MatchRule("(SignExtend FloatingRead=access)")
-    public static class SignExtend extends AMD64MatchGenerator {
-        Access access;
-        SignExtendNode root;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return gen.emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
-        }
-    }
-
-    static abstract class AMD64MatchGenerator implements MatchGenerator {
-        public AMD64MatchGenerator() {
-        }
-
-        public ComplexMatchResult match(NodeLIRBuilder gen) {
-            return match((AMD64NodeLIRBuilder) gen);
-        }
-
-        abstract public ComplexMatchResult match(AMD64NodeLIRBuilder gen);
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
     }
 
     @MatchRule("(ZeroExtend Read=access)")
     @MatchRule("(ZeroExtend FloatingRead=access)")
-    public static class ZeroExtend extends AMD64MatchGenerator {
-        Access access;
-        ZeroExtendNode root;
-
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            Kind memoryKind = gen.getMemoryKind(access);
-            if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) {
-                /*
-                 * The memory being read from is signed and smaller than the result size so this is
-                 * a sign extension to inputBits followed by a zero extension to resultBits which
-                 * can't be expressed in a memory operation.
-                 */
-                return null;
-            }
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder unused) {
-                    return gen.getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), gen.makeAddress(access), gen.getState(access));
-                }
-            };
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        Kind memoryKind = getMemoryKind(access);
+        if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) {
+            /*
+             * The memory being read from is signed and smaller than the result size so this is a
+             * sign extension to inputBits followed by a zero extension to resultBits which can't be
+             * expressed in a memory operation.
+             */
+            return null;
         }
+        return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), makeAddress(access), getState(access));
     }
 
     @MatchRule("(FloatConvert Read=access)")
     @MatchRule("(FloatConvert FloatingRead=access)")
-    public static class FloatConvert extends AMD64MatchGenerator {
-        Access access;
-        FloatConvertNode root;
+    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
+        return builder -> emitFloatConvertMemory(root, access);
 
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    return gen.emitFloatConvertMemory(root, access);
-                }
-            };
-        }
     }
 
     @MatchRule("(Reinterpret Read=access)")
     @MatchRule("(Reinterpret FloatingRead=access)")
-    public static class Reinterpret extends AMD64MatchGenerator {
-        Access access;
-        ReinterpretNode root;
+    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
+        return builder -> {
+            PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp());
+            return emitReinterpretMemory(kind, access);
+        };
 
-        @Override
-        public ComplexMatchResult match(AMD64NodeLIRBuilder gen) {
-            return new ComplexMatchResult() {
-                public Value evaluate(NodeLIRBuilder builder) {
-                    PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(root.stamp());
-                    return gen.emitReinterpretMemory(kind, access);
-                }
-            };
-        }
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Fri May 02 02:45:26 2014 +0200
@@ -70,6 +70,8 @@
             return enabled;
         }
     };
+    @Option(help = "Enable more verbose log output when available")
+    public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
     // @formatter:on
 
     public static boolean areDebugScopePatternsEnabled() {
@@ -150,7 +152,7 @@
 
     /**
      * Extracts a {@link JavaMethod} from an opaque debug context.
-     * 
+     *
      * @return the {@link JavaMethod} represented by {@code context} or null
      */
     public static JavaMethod asJavaMethod(Object context) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri May 02 02:45:26 2014 +0200
@@ -170,7 +170,7 @@
      * ValueNodes.
      */
     public void setMatchResult(ValueNode x, Value operand) {
-        assert operand.equals(Value.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
+        assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue;
         assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user";
         assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice";
         assert !(x instanceof VirtualObjectNode);
@@ -237,7 +237,7 @@
                             throw new GraalGraphInternalError(e).addContext(instr);
                         }
                     }
-                } else if (Value.INTERIOR_MATCH.equals(operand)) {
+                } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) {
                     // Doesn't need to be evaluated
                     Debug.log("interior match for %s", valueNode);
                 } else if (operand instanceof ComplexMatchValue) {
@@ -285,7 +285,7 @@
                     List<MatchStatement> statements = matchRules.get(node.getClass());
                     if (statements != null) {
                         for (MatchStatement statement : statements) {
-                            if (statement.generate(this, node, nodes)) {
+                            if (statement.generate(this, index, node, nodes)) {
                                 // Found a match so skip to the next
                                 break;
                             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java	Fri May 02 02:45:26 2014 +0200
@@ -25,10 +25,10 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 
-/*
- * A closure that can be evaluated to produce the LIR for some complex match. Using a closure
- * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes
- * evaluated at the proper time.
+/**
+ * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows
+ * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at
+ * the proper time.
  */
 public interface ComplexMatchResult {
     Value evaluate(NodeLIRBuilder gen);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java	Fri May 02 02:45:26 2014 +0200
@@ -31,10 +31,25 @@
  * usually occur here.
  */
 public class ComplexMatchValue extends Value {
+    private static final long serialVersionUID = -4734670273590368770L;
+
     /**
-     *
+     * This is the Value of a node which was matched as part of a complex match. The value isn't
+     * actually useable but this marks it as having been evaluated.
      */
-    private static final long serialVersionUID = -4734670273590368770L;
+    @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) {
+
+        @Override
+        public String toString() {
+            return "INTERIOR_MATCH";
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            // This class is a singleton
+            return other != null && getClass() == other.getClass();
+        }
+    };
 
     final ComplexMatchResult result;
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Fri May 02 02:45:26 2014 +0200
@@ -30,34 +30,34 @@
  * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in
  * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here.
  */
-@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0)
-@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
-@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class)
-@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
-@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class)
-@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
-@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class)
-@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
-@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
-@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = ConstantNode.class, inputs = 0)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(nodeClass = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(nodeClass = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(nodeClass = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class)
+@MatchableNode(nodeClass = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(nodeClass = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(nodeClass = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(nodeClass = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class)
+@MatchableNode(nodeClass = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class)
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class)
+@MatchableNode(nodeClass = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class)
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class)
+@MatchableNode(nodeClass = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
+@MatchableNode(nodeClass = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true)
 public class GraalMatchableNodes {
     public static class BinaryNodeAdapter extends MatchNodeAdapter {
         @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Fri May 02 02:45:26 2014 +0200
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.compiler.match;
 
-import java.lang.reflect.*;
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
 import java.util.*;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.match.MatchPattern.Result;
@@ -38,24 +38,41 @@
  * Container for state captured during a match.
  */
 public class MatchContext {
-    private final ArrayList<ValueNode> consumed = new ArrayList<>();
-    private final List<ScheduledNode> nodes;
+
     private final ValueNode root;
-    private List<String> names;
-    private List<Class<? extends ValueNode>> types;
-    private List<ValueNode> values;
+
+    private final List<ScheduledNode> nodes;
+
     private final MatchStatement rule;
+
+    private Map<String, NamedNode> namedNodes;
+
+    private ArrayList<ValueNode> consumed;
+
     private int startIndex;
+
     private int endIndex;
+
     private final NodeLIRBuilder builder;
 
-    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List<ScheduledNode> nodes) {
+    private static class NamedNode {
+        final Class<? extends ValueNode> type;
+        final ValueNode value;
+
+        NamedNode(Class<? extends ValueNode> type, ValueNode value) {
+            this.type = type;
+            this.value = value;
+        }
+    }
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List<ScheduledNode> nodes) {
         this.builder = builder;
         this.rule = rule;
         this.root = node;
         this.nodes = nodes;
-        // The root should be the last index since all the inputs must be scheduled before.
-        startIndex = endIndex = nodes.indexOf(node);
+        assert index == nodes.indexOf(node);
+        // The root should be the last index since all the inputs must be scheduled before it.
+        startIndex = endIndex = index;
     }
 
     public ValueNode getRoot() {
@@ -63,19 +80,16 @@
     }
 
     public Result captureNamedValue(String name, Class<? extends ValueNode> type, ValueNode value) {
-        if (names == null) {
-            names = new ArrayList<>(2);
-            values = new ArrayList<>(2);
-            types = new ArrayList<>(2);
+        if (namedNodes == null) {
+            namedNodes = new HashMap<>(2);
         }
-        int index = names.indexOf(name);
-        if (index == -1) {
-            names.add(name);
-            values.add(value);
-            types.add(type);
+        NamedNode current = namedNodes.get(name);
+        if (current == null) {
+            current = new NamedNode(type, value);
+            namedNodes.put(name, current);
             return Result.OK;
         } else {
-            if (values.get(index) != value) {
+            if (current.value != value || current.type != type) {
                 return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern());
             }
             return Result.OK;
@@ -85,20 +99,19 @@
     public Result validate() {
         // Ensure that there's no unsafe work in between these operations.
         for (int i = startIndex; i <= endIndex; i++) {
-            ScheduledNode node = getNodes().get(i);
+            ScheduledNode node = nodes.get(i);
             if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) {
                 // these can be evaluated lazily so don't worry about them. This should probably be
                 // captured by some interface that indicates that their generate method is empty.
                 continue;
-            } else if (!consumed.contains(node) && node != root) {
-                // This is too verbose for normal logging.
-                // Debug.log("unexpected node %s", node);
-                // for (int j = startIndex; j <= endIndex; j++) {
-                // ScheduledNode theNode = getNodes().get(j);
-                // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" :
-                // " ",
-                // theNode.usages().count(), theNode);
-                // }
+            } else if (consumed == null || !consumed.contains(node) && node != root) {
+                if (LogVerbose.getValue()) {
+                    Debug.log("unexpected node %s", node);
+                    for (int j = startIndex; j <= endIndex; j++) {
+                        ScheduledNode theNode = nodes.get(j);
+                        Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
+                    }
+                }
                 return Result.NOT_SAFE(node, rule.getPattern());
             }
         }
@@ -106,56 +119,24 @@
     }
 
     /**
-     * Transfers the captured value into the MatchGenerator instance. The reflective information
-     * should really be generated and checking during construction of the MatchStatement but this is
-     * ok for now.
-     */
-    public void transferState(MatchGenerator generator) {
-        try {
-            for (int i = 0; i < names.size(); i++) {
-                String name = names.get(i);
-                try {
-                    Field field = generator.getClass().getDeclaredField(name);
-                    field.setAccessible(true);
-                    field.set(generator, values.get(i));
-                } catch (NoSuchFieldException e) {
-                    // Doesn't exist so the generator doesn't care about the value.
-                }
-            }
-        } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
-            throw new GraalInternalError(e);
-        }
-        try {
-            Field field = generator.getClass().getDeclaredField("root");
-            field.setAccessible(true);
-            field.set(generator, getRoot());
-        } catch (NoSuchFieldException e) {
-            // Doesn't exist
-        } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    public void setResult(ComplexMatchResult result) {
-        setResult(new ComplexMatchValue(result));
-    }
-
-    /**
      * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
      * During final LIR generation it will be evaluated to produce the actual LIR value.
      *
      * @param result
      */
-    public void setResult(ComplexMatchValue result) {
+    public void setResult(ComplexMatchResult result) {
+        ComplexMatchValue value = new ComplexMatchValue(result);
         Debug.log("matched %s %s", rule.getName(), rule.getPattern());
-        // Debug.log("%s", rule.formatMatch(root));
-        for (ValueNode node : consumed) {
-            // All the interior nodes should be skipped during the normal doRoot calls in
-            // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
-            // closure which will be evaluated to produce the final LIR.
-            getBuilder().setMatchResult(node, Value.INTERIOR_MATCH);
+        Debug.log("with nodes %s", rule.formatMatch(root));
+        if (consumed != null) {
+            for (ValueNode node : consumed) {
+                // All the interior nodes should be skipped during the normal doRoot calls in
+                // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+                // closure which will be evaluated to produce the final LIR.
+                builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH);
+            }
         }
-        getBuilder().setMatchResult(root, result);
+        builder.setMatchResult(root, value);
     }
 
     /**
@@ -164,28 +145,43 @@
      * @return Result.OK if the node can be safely consumed.
      */
     public Result consume(ValueNode node) {
-        if (node.usages().count() != 1) {
-            return Result.TOO_MANY_USERS(node, rule.getPattern());
-        }
+        assert node.usages().count() <= 1 : "should have already been checked";
 
-        if (getBuilder().hasOperand(node)) {
+        if (builder.hasOperand(node)) {
             return Result.ALREADY_USED(node, rule.getPattern());
         }
 
-        int index = getNodes().indexOf(node);
+        int index = nodes.indexOf(node);
         if (index == -1) {
             return Result.NOT_IN_BLOCK(node, rule.getPattern());
         }
         startIndex = Math.min(startIndex, index);
+        if (consumed == null) {
+            consumed = new ArrayList<>(2);
+        }
         consumed.add(node);
         return Result.OK;
     }
 
-    private NodeLIRBuilder getBuilder() {
-        return builder;
+    /**
+     * Return the named node. It's an error if the
+     *
+     * @param name the name of a node in the match rule
+     * @return the matched node
+     * @throws GraalInternalError is the named node doesn't exist.
+     */
+    public ValueNode namedNode(String name) {
+        if (namedNodes != null) {
+            NamedNode value = namedNodes.get(name);
+            if (value != null) {
+                return value.value;
+            }
+        }
+        throw new GraalInternalError("missing node %s", name);
     }
 
-    private List<ScheduledNode> getNodes() {
-        return nodes;
+    @Override
+    public String toString() {
+        return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : "");
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Fri May 02 02:45:26 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.match;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 
@@ -47,7 +48,9 @@
      */
     static class Result {
         final MatchResultCode code;
+
         final ScheduledNode node;
+
         final MatchPattern matcher;
 
         Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) {
@@ -56,29 +59,42 @@
             this.matcher = matcher;
         }
 
+        private static final DebugMetric MatchResult_WRONG_CLASS = Debug.metric("MatchResult_WRONG_CLASS");
+        private static final DebugMetric MatchResult_NAMED_VALUE_MISMATCH = Debug.metric("MatchResult_NAMED_VALUE_MISMATCH");
+        private static final DebugMetric MatchResult_TOO_MANY_USERS = Debug.metric("MatchResult_TOO_MANY_USERS");
+        private static final DebugMetric MatchResult_NOT_IN_BLOCK = Debug.metric("MatchResult_NOT_IN_BLOCK");
+        private static final DebugMetric MatchResult_NOT_SAFE = Debug.metric("MatchResult_NOT_SAFE");
+        private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED");
+
         static final Result OK = new Result(MatchResultCode.OK, null, null);
 
         static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) {
+            MatchResult_WRONG_CLASS.increment();
             return new Result(MatchResultCode.WRONG_CLASS, node, matcher);
         }
 
         static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) {
+            MatchResult_NAMED_VALUE_MISMATCH.increment();
             return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher);
         }
 
         static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) {
+            MatchResult_TOO_MANY_USERS.increment();
             return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher);
         }
 
         static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_IN_BLOCK.increment();
             return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher);
         }
 
         static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) {
+            MatchResult_NOT_SAFE.increment();
             return new Result(MatchResultCode.NOT_SAFE, node, matcher);
         }
 
         static Result ALREADY_USED(ValueNode node, MatchPattern matcher) {
+            MatchResult_ALREADY_USED.increment();
             return new Result(MatchResultCode.ALREADY_USED, node, matcher);
         }
 
@@ -143,14 +159,32 @@
         return nodeClass;
     }
 
-    Result match(ValueNode node, MatchContext context) {
-        return matchTree(node, context, true);
+    private Result matchType(ValueNode node) {
+        if (nodeClass != null && node.getClass() != nodeClass) {
+            return Result.WRONG_CLASS(node, this);
+        }
+        return Result.OK;
     }
 
-    private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) {
-        Result result = Result.OK;
-        if (nodeClass != null && node.getClass() != nodeClass) {
-            return Result.WRONG_CLASS(node, this);
+    /**
+     * Match any named nodes and ensure that the consumed nodes can be safely merged.
+     *
+     * @param node
+     * @param context
+     * @return Result.OK is the pattern can be safely matched.
+     */
+    Result matchUsage(ValueNode node, MatchContext context) {
+        Result result = matchUsage(node, context, true);
+        if (result == Result.OK) {
+            result = context.validate();
+        }
+        return result;
+    }
+
+    private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
         }
         if (singleUser && !atRoot) {
             result = context.consume(node);
@@ -164,9 +198,43 @@
         }
 
         if (first != null) {
-            result = first.matchTree(adapter.getFirstInput(node), context, false);
+            result = first.matchUsage(adapter.getFirstInput(node), context, false);
             if (result == Result.OK && second != null) {
-                result = second.matchTree(adapter.getSecondInput(node), context, false);
+                result = second.matchUsage(adapter.getSecondInput(node), context, false);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Recursively match the shape of the tree without worry about named values. Most matches fail
+     * at this point so it's performed first.
+     *
+     * @param node
+     * @param statement
+     * @return Result.OK if the shape of the pattern matches.
+     */
+    public Result matchShape(ValueNode node, MatchStatement statement) {
+        return matchShape(node, statement, true);
+    }
+
+    private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) {
+        Result result = matchType(node);
+        if (result != Result.OK) {
+            return result;
+        }
+
+        if (singleUser && !atRoot) {
+            if (node.usages().count() > 1) {
+                return Result.TOO_MANY_USERS(node, statement.getPattern());
+            }
+        }
+
+        if (first != null) {
+            result = first.matchShape(adapter.getFirstInput(node), statement, false);
+            if (result == Result.OK && second != null) {
+                result = second.matchShape(adapter.getSecondInput(node), statement, false);
             }
         }
 
@@ -195,7 +263,8 @@
             String pre = first != null || second != null ? "(" : "";
             String post = first != null || second != null ? ")" : "";
             String nodeName = nodeClass.getSimpleName();
-            return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
+            nodeName = nodeName.substring(0, nodeName.length() - 4);
+            return pre + nodeName + (name != null ? "=" + name : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Fri May 02 02:45:26 2014 +0200
@@ -30,6 +30,7 @@
 import javax.lang.model.*;
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
+import javax.lang.model.util.*;
 import javax.tools.Diagnostic.Kind;
 import javax.tools.*;
 
@@ -63,14 +64,23 @@
     private static class RuleParseError extends RuntimeException {
         private static final long serialVersionUID = 6456128283609257490L;
 
-        RuleParseError(String message) {
-            super(message);
+        RuleParseError(String format, Object... args) {
+            super(String.format(format, args));
         }
     }
 
     private class RuleParser {
-        final String[] tokens;
-        int current;
+        private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
+
+        private ArrayList<String> capturedNames = new ArrayList<>();
+
+        private final String[] tokens;
+
+        private int current;
+
+        private MatchDescriptor matchDescriptor;
+
+        private final Set<Element> originatingElements = new HashSet<>();
 
         RuleParser(String rule) {
             Matcher m = tokenizer.matcher(rule);
@@ -82,16 +92,29 @@
                 m.region(m.end(), m.regionEnd());
             }
             if (end != m.regionEnd()) {
-                throw new RuleParseError("unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+                throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
             }
             tokens = list.toArray(new String[0]);
+
+            matchDescriptor = parseExpression();
+            if (!done()) {
+                throw new RuleParseError("didn't consume all tokens");
+            }
+            capturedNames.add(0, "root");
+            capturedTypes.add(0, matchDescriptor.nodeType);
         }
 
         String next() {
             return tokens[current++];
         }
 
-        String peek() {
+        String peek(String name) {
+            if (current >= tokens.length) {
+                if (name == null) {
+                    throw new RuleParseError("Out of tokens");
+                }
+                throw new RuleParseError("Out of tokens looking for %s", name);
+            }
             return tokens[current];
         }
 
@@ -99,13 +122,13 @@
             return current == tokens.length;
         }
 
-        private MatchDescriptor parseSexp() {
-            if (peek().equals("(")) {
+        private MatchDescriptor parseExpression() {
+            if (peek("(").equals("(")) {
                 next();
                 MatchDescriptor descriptor = parseType(true);
                 for (int n = 0; n < descriptor.nodeType.inputs; n++) {
-                    if (peek().equals("(")) {
-                        descriptor.inputs[n] = parseSexp();
+                    if (peek("(").equals("(")) {
+                        descriptor.inputs[n] = parseExpression();
                     } else {
                         descriptor.inputs[n] = parseType(false);
                     }
@@ -115,46 +138,70 @@
                         throw new RuleParseError("not enough inputs for " + descriptor.name);
                     }
                 }
-                if (peek().equals(")")) {
+                if (peek(")").equals(")")) {
                     next();
                     return descriptor;
                 }
             }
-            throw new RuleParseError("didn't swallow sexp at: " + peek());
+            throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
         }
 
-        private MatchDescriptor parseType(boolean sexp) {
+        private MatchDescriptor parseType(boolean forExpression) {
             TypeDescriptor type = null;
             String name = null;
-            if (Character.isUpperCase(peek().charAt(0))) {
+            if (Character.isUpperCase(peek("node type or name").charAt(0))) {
                 String token = next();
-                type = types.get(token);
+                type = knownTypes.get(token);
                 if (type == null) {
-                    throw new RuleParseError("unknown node type: " + token);
+                    throw new RuleParseError("Unknown node type: " + token);
                 }
-                if (peek().equals("=")) {
+                if (peek("=").equals("=")) {
                     next();
                     name = next();
                 }
-            } else {
+                originatingElements.addAll(type.originatingElements);
+            } else if (Character.isLowerCase(peek("name").charAt(0))) {
                 name = next();
-                type = null;
+                type = valueType;
+            } else {
+                throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
             }
-            return new MatchDescriptor(type, name, sexp);
+            if (name != null) {
+                if (!capturedNames.contains(name)) {
+                    capturedNames.add(name);
+                    capturedTypes.add(type);
+                } else {
+                    int index = capturedNames.indexOf(name);
+                    if (capturedTypes.get(index) != type) {
+                        throw new RuleParseError("Captured node \"%s\" has differing types", name);
+                    }
+                }
+            }
+            return new MatchDescriptor(type, name, forExpression);
         }
 
-        ArrayList<String> generateVariants() {
-            MatchDescriptor descriptor = parseSexp();
-            if (!done()) {
-                throw new RuleParseError("didn't consume all tokens");
-            }
-            return descriptor.generateVariants();
+        List<String> generateVariants() {
+            return matchDescriptor.generateVariants();
+        }
+
+        /**
+         *
+         * @return the list of node types which are captured by name
+         */
+        public ArrayList<TypeDescriptor> capturedTypes() {
+            return capturedTypes;
+        }
+
+        public ArrayList<String> capturedNames() {
+            return capturedNames;
         }
     }
 
     static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
 
     static class TypeDescriptor {
+        final TypeMirror mirror;
+
         /**
          * The name uses in match expressions to refer to this type.
          */
@@ -192,7 +239,10 @@
          */
         final boolean cloneable;
 
-        TypeDescriptor(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+        final Set<Element> originatingElements = new HashSet<>();
+
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+            this.mirror = mirror;
             this.shortName = shortName;
             this.nodeClass = nodeClass;
             this.nodePackage = nodePackage;
@@ -204,14 +254,28 @@
         }
     }
 
-    HashMap<String, TypeDescriptor> types = new HashMap<>();
-    ArrayList<String> packages = new ArrayList<>();
+    /**
+     * The types which are know for purpose of parsing MatchRule expressions.
+     */
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
+
+    /**
+     * The set of packages which must be imported to refer to the known classes.
+     */
+    List<String> requiredPackages = new ArrayList<>();
 
-    private void declareType(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
-        TypeDescriptor descriptor = new TypeDescriptor(shortName, nodeClass, nodePackage, inputs, adapter, commutative);
-        types.put(shortName, descriptor);
-        if (!packages.contains(descriptor.nodePackage)) {
-            packages.add(descriptor.nodePackage);
+    /**
+     * The automatically generated wrapper class for a method based MatchRule.
+     */
+    private Map<ExecutableElement, MethodInvokerItem> invokers = new LinkedHashMap<>();
+    private TypeDescriptor valueType;
+
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, Element element) {
+        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, adapter, commutative);
+        descriptor.originatingElements.add(element);
+        knownTypes.put(shortName, descriptor);
+        if (!requiredPackages.contains(descriptor.nodePackage)) {
+            requiredPackages.add(descriptor.nodePackage);
         }
     }
 
@@ -226,22 +290,28 @@
         throw new GraalInternalError("can't find package for %s", type);
     }
 
-    static class MatchDescriptor {
+    class MatchDescriptor {
         TypeDescriptor nodeType;
         String name;
         MatchDescriptor[] inputs;
 
-        MatchDescriptor(TypeDescriptor nodeType, String name, boolean sexp) {
+        MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) {
             this.nodeType = nodeType;
             this.name = name;
-            if (sexp) {
+            if (forExpression) {
                 this.inputs = new MatchDescriptor[nodeType.inputs];
             } else {
                 this.inputs = new MatchDescriptor[0];
             }
         }
 
-        ArrayList<String> generateVariants() {
+        /**
+         * Recursively generate all the variants of this rule pattern. Currently that just means to
+         * swap the inputs for commutative rules, producing all possible permutations.
+         *
+         * @return a list of Strings which will construct pattern matchers for this rule.
+         */
+        List<String> generateVariants() {
             String prefix = formatPrefix();
             String suffix = formatSuffix();
             ArrayList<String> variants = new ArrayList<>();
@@ -266,7 +336,7 @@
         }
 
         private String formatPrefix() {
-            if (nodeType == null) {
+            if (nodeType == valueType) {
                 return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
             } else {
                 return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
@@ -291,15 +361,25 @@
 
     }
 
+    /**
+     * Strip the package off a class name leaving the full class name including any outer classes.
+     */
+    static String fullClassName(Element element) {
+        assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element;
+        String pkg = findPackage(element);
+        return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1);
+    }
+
     private void createFiles(MatchRuleDescriptor info) {
         String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
         Name topDeclaringClass = info.topDeclaringType.getSimpleName();
 
-        String optionsClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+        String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
         Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
 
+        Types typeUtils = processingEnv.getTypeUtils();
         Filer filer = processingEnv.getFiler();
-        try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) {
+        try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
 
             out.println("// CheckStyle: stop header check");
             out.println("// GENERATED CONTENT - DO NOT EDIT");
@@ -307,29 +387,56 @@
             out.println("package " + pkg + ";");
             out.println("");
             out.println("import java.util.*;");
+            out.println("import java.lang.reflect.*;");
             out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
+            out.println("import " + GraalInternalError.class.getName() + ";");
             out.println("import " + NodeLIRBuilder.class.getName() + ";");
-            for (String p : packages) {
+            for (String p : requiredPackages) {
                 out.println("import " + p + ".*;");
             }
             out.println("");
-            out.println("public class " + optionsClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+            out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+
+            // Generate declarations for the reflective invocation of the code generation methods.
+            for (MethodInvokerItem invoker : invokers.values()) {
+                StringBuilder args = new StringBuilder();
+                StringBuilder types = new StringBuilder();
+                int count = invoker.fields.size();
+                for (VariableElement arg : invoker.fields) {
+                    args.append('"');
+                    args.append(arg.getSimpleName());
+                    args.append('"');
+                    types.append(fullClassName(typeUtils.asElement(arg.asType())));
+                    types.append(".class");
+                    if (count-- > 1) {
+                        args.append(", ");
+                        types.append(", ");
+                    }
+                }
+                out.printf("        private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
+                out.printf("        private static final Method %s;\n", invoker.reflectiveMethodName());
+                out.printf("        static {\n");
+                out.printf("            Method result = null;\n");
+                out.printf("            try {\n");
+                out.printf("                result = %s.class.getDeclaredMethod(\"%s\", %s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
+                out.printf("             } catch (Exception e) {\n");
+                out.printf("                 throw new GraalInternalError(e);\n");
+                out.printf("             }\n");
+                out.printf("             %s = result;\n", invoker.reflectiveMethodName());
+                out.printf("        }\n");
+
+                out.println();
+
+            }
+
             String desc = MatchStatement.class.getSimpleName();
             out.println("    // CheckStyle: stop line length check");
-            out.println("    private static final List<" + desc + "> options = Collections.unmodifiableList(Arrays.asList(");
+            out.println("    private static final List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList(");
 
             int i = 0;
-            for (MatchRuleItem option : info.options) {
-                String optionValue;
-                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
-                    optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")";
-                } else {
-                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
-                }
-                String name = option.name;
-                Name fieldName = option.field.getSimpleName();
-                String comma = i == info.options.size() - 1 ? "" : ",";
-                out.printf("        new MatchStatement(\"%s\", %s, %s.class)%s\n", fieldName, name, optionValue, comma);
+            for (MatchRuleItem matchRule : info.matchRules) {
+                String comma = i == info.matchRules.size() - 1 ? "" : ",";
+                out.printf("        %s%s\n", matchRule.ruleBuilder(), comma);
                 i++;
             }
             out.println("    ));");
@@ -342,13 +449,13 @@
             out.println();
             out.println("    @Override");
             out.println("    public List<" + desc + "> statements() {");
-            out.println("        return options;");
+            out.println("        return statements;");
             out.println("    }");
             out.println("}");
         }
 
         try {
-            createProviderFile(pkg, optionsClassName, originatingElements);
+            createProviderFile(pkg, matchStatementClassName, originatingElements);
         } catch (IOException e) {
             processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType);
         }
@@ -378,34 +485,57 @@
         }
     }
 
-    static class MatchRuleItem implements Comparable<MatchRuleItem> {
+    /**
+     * Used to generate the MatchStatement constructor invocation.
+     */
+    static class MatchRuleItem {
+        private final String matchPattern;
+        private final MethodInvokerItem invoker;
 
-        final String name;
-        final String declaringClass;
-        final TypeElement field;
-
-        public MatchRuleItem(String name, String declaringClass, TypeElement field) {
-            this.name = name;
-            this.declaringClass = declaringClass;
-            this.field = field;
+        public MatchRuleItem(String matchPattern, MethodInvokerItem invoker) {
+            this.matchPattern = matchPattern;
+            this.invoker = invoker;
         }
 
-        @Override
-        public int compareTo(MatchRuleItem other) {
-            return name.compareTo(other.name);
+        /**
+         * @return a string which will construct the MatchStatement instance to match this pattern.
+         */
+        public String ruleBuilder() {
+            return String.format("new MatchStatement(\"%s\", %s, %s, %s)", invoker.name, matchPattern, invoker.reflectiveMethodName(), invoker.argumentsListName());
+        }
+    }
+
+    /**
+     * Used to generate the declarations needed for reflective invocation of the code generation
+     * method.
+     */
+    static class MethodInvokerItem {
+        final String name;
+        final String nodeLIRBuilderClass;
+        final String methodName;
+        final List<? extends VariableElement> fields;
+
+        MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List<? extends VariableElement> fields) {
+            this.name = name;
+            this.nodeLIRBuilderClass = nodeLIRBuilderClass;
+            this.methodName = methodName;
+            this.fields = fields;
         }
 
-        @Override
-        public String toString() {
-            return declaringClass + "." + field;
+        String reflectiveMethodName() {
+            return methodName + "_invoke";
+        }
+
+        String argumentsListName() {
+            return methodName + "_arguments";
         }
     }
 
     static class MatchRuleDescriptor {
 
         final TypeElement topDeclaringType;
-        final List<MatchRuleItem> options = new ArrayList<>();
-        final Set<Element> originatingElements = new HashSet<>();
+        final List<MatchRuleItem> matchRules = new ArrayList<>();
+        private final Set<Element> originatingElements = new HashSet<>();
 
         public MatchRuleDescriptor(TypeElement topDeclaringType) {
             this.topDeclaringType = topDeclaringType;
@@ -428,6 +558,11 @@
         }
 
         try {
+            // Define a TypeDescriptor the generic node but don't enter it into the nodeTypes table
+            // since it shouldn't mentioned in match rules.
+            TypeMirror mirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
+            valueType = new TypeDescriptor(mirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false);
+
             // Import default definitions
             processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName()));
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) {
@@ -457,7 +592,7 @@
             }
 
         } catch (Throwable t) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t);
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)));
         }
 
         return true;
@@ -468,107 +603,170 @@
      */
     private void processMatchableNode(Element element) {
         if (!processedMatchableNode.contains(element)) {
-            processedMatchableNode.add(element);
-            TypeElement topDeclaringType = topDeclaringType(element);
-            MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class);
-            for (MatchableNode matchable : matchables) {
-                String nodeClass;
-                String nodePackage;
-                String shortName = matchable.shortName();
-                TypeMirror nodeClassMirror = null;
-                try {
-                    matchable.value();
-                } catch (MirroredTypeException e) {
-                    nodeClassMirror = e.getTypeMirror();
-                }
-                if (nodeClassMirror == null) {
-                    throw new GraalInternalError("Can't get mirror for node class %s", element);
+            try {
+                processedMatchableNode.add(element);
+                TypeElement topDeclaringType = topDeclaringType(element);
+                MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class);
+                for (MatchableNode matchable : matchables) {
+                    String nodeClass;
+                    String nodePackage;
+                    TypeMirror nodeClassMirror = null;
+                    try {
+                        matchable.nodeClass();
+                    } catch (MirroredTypeException e) {
+                        nodeClassMirror = e.getTypeMirror();
+                    }
+                    if (nodeClassMirror == null) {
+                        throw new GraalInternalError("Can't get mirror for node class %s", element);
+                    }
+                    if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+                        nodeClass = topDeclaringType.getQualifiedName().toString();
+                    } else {
+                        nodeClass = nodeClassMirror.toString();
+                    }
+                    nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass));
+                    assert nodeClass.startsWith(nodePackage);
+                    nodeClass = nodeClass.substring(nodePackage.length() + 1);
+                    assert nodeClass.endsWith("Node");
+                    String shortName = nodeClass.substring(0, nodeClass.length() - 4);
+
+                    TypeMirror nodeAdapterMirror = null;
+                    try {
+                        matchable.adapter();
+                    } catch (MirroredTypeException e) {
+                        nodeAdapterMirror = e.getTypeMirror();
+                    }
+                    if (nodeAdapterMirror == null) {
+                        throw new GraalInternalError("Can't get mirror for adapter %s", element);
+                    }
+                    String nodeAdapter = null;
+                    if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) {
+                        nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString());
+                    }
+
+                    declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), element);
                 }
-                if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
-                    nodeClass = topDeclaringType.getQualifiedName().toString();
-                } else {
-                    nodeClass = nodeClassMirror.toString();
-                }
-                nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass));
-                assert nodeClass.startsWith(nodePackage);
-                nodeClass = nodeClass.substring(nodePackage.length() + 1);
-
-                TypeMirror nodeAdapterMirror = null;
-                try {
-                    matchable.adapter();
-                } catch (MirroredTypeException e) {
-                    nodeAdapterMirror = e.getTypeMirror();
-                }
-                if (nodeAdapterMirror == null) {
-                    throw new GraalInternalError("Can't get mirror for adapter %s", element);
-                }
-                String nodeAdapter = null;
-                if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) {
-                    nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString());
-                }
-
-                declareType(shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative());
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
             }
         }
     }
 
+    private void reportExceptionThrow(Element element, Throwable t) {
+        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)), element);
+    }
+
     private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element) {
         if (!processedMatchRule.contains(element)) {
-            processedMatchRule.add(element);
-            TypeElement topDeclaringType = topDeclaringType(element);
-            MatchRuleDescriptor options = map.get(topDeclaringType);
-            if (options == null) {
-                options = new MatchRuleDescriptor(topDeclaringType);
-                map.put(topDeclaringType, options);
-            }
-            MatchRule[] matchRules = element.getAnnotationsByType(MatchRule.class);
-            for (MatchRule matchRule : matchRules) {
-                processMatchRule(element, options, matchRule);
+            try {
+                processedMatchRule.add(element);
+
+                // The annotation element type should ensure this is true.
+                assert element instanceof ExecutableElement;
+
+                TypeElement topDeclaringType = topDeclaringType(element);
+                MatchRuleDescriptor info = map.get(topDeclaringType);
+                if (info == null) {
+                    info = new MatchRuleDescriptor(topDeclaringType);
+                    map.put(topDeclaringType, info);
+                }
+                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
+                    // System.err.println(matchRule);
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule);
+                }
+            } catch (Throwable t) {
+                reportExceptionThrow(element, t);
             }
         }
     }
 
-    private void processMatchRule(Element element, MatchRuleDescriptor info, MatchRule matchRule) {
-        assert element instanceof TypeElement;
-        assert element.getKind() == ElementKind.CLASS;
-        TypeElement field = (TypeElement) element;
+    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) {
+        Types typeUtils = processingEnv.getTypeUtils();
 
-        TypeMirror fieldType = field.asType();
-        if (fieldType.getKind() != TypeKind.DECLARED) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + MatchRule.class.getName(), element);
+        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
+            String msg = String.format("MatchRule method %s must be public", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+            return;
+        }
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
             return;
         }
 
-        Element enclosing = element.getEnclosingElement();
-        String declaringClass = "";
-        String separator = "";
-        Set<Element> originatingElementsList = info.originatingElements;
-        originatingElementsList.add(field);
-        while (enclosing != null) {
-            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
-                if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
-                    String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
-                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+        try {
+            TypeMirror returnType = method.getReturnType();
+            if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
+                String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            String rule = matchRule.value();
+            RuleParser parser = new RuleParser(rule);
+            ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
+            ArrayList<String> expectedNames = parser.capturedNames();
+            List<? extends VariableElement> actualParameters = method.getParameters();
+            if (expectedTypes.size() + 1 < actualParameters.size()) {
+                String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                return;
+            }
+
+            // Walk through the parameters to the method and see if they exist in the match rule.
+            // The order doesn't matter but only names mentioned in the rule can be used and they
+            // must be assignment compatible.
+            for (VariableElement parameter : actualParameters) {
+                String name = parameter.getSimpleName().toString();
+                int nameIndex = expectedNames.indexOf(name);
+                if (nameIndex == -1) {
+                    String msg = String.format("Argument \"%s\" isn't captured in the match rule", name);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                    return;
+                }
+                TypeMirror type = parameter.asType();
+                if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
+                    String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
                     return;
                 }
-                originatingElementsList.add(enclosing);
-                declaringClass = enclosing.getSimpleName() + separator + declaringClass;
-                separator = ".";
-            } else {
-                assert enclosing.getKind() == ElementKind.PACKAGE;
+            }
+
+            MethodInvokerItem invoker = invokers.get(method);
+            if (invoker == null) {
+                invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters);
+                invokers.put(method, invoker);
             }
-            enclosing = enclosing.getEnclosingElement();
-        }
 
-        String rule = matchRule.value();
-        try {
-            ArrayList<String> matches = new RuleParser(rule).generateVariants();
+            Element enclosing = method.getEnclosingElement();
+            String declaringClass = "";
+            String separator = "";
+            Set<Element> originatingElementsList = info.originatingElements;
+            originatingElementsList.add(method);
+            while (enclosing != null) {
+                if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                    if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                        String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                        processingEnv.getMessager().printMessage(Kind.ERROR, msg, method);
+                        return;
+                    }
+                    originatingElementsList.add(enclosing);
+                    declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                    separator = ".";
+                } else {
+                    assert enclosing.getKind() == ElementKind.PACKAGE;
+                }
+                enclosing = enclosing.getEnclosingElement();
+            }
+
+            originatingElementsList.addAll(parser.originatingElements);
+
+            List<String> matches = parser.generateVariants();
             for (String match : matches) {
-                info.options.add(new MatchRuleItem(match, declaringClass, field));
+                info.matchRules.add(new MatchRuleItem(match, invoker));
             }
         } catch (RuleParseError e) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), element);
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method);
         }
     }
-
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Fri May 02 02:45:26 2014 +0200
@@ -43,7 +43,7 @@
  */
 
 @Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
+@Target(ElementType.METHOD)
 @Repeatable(value = MatchRules.class)
 public @interface MatchRule {
     String value();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Fri May 02 02:45:26 2014 +0200
@@ -22,9 +22,14 @@
  */
 package com.oracle.graal.compiler.match;
 
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
 import java.util.*;
+import java.util.Map.Entry;
 
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
 import com.oracle.graal.nodes.*;
 
 public class MatchRuleRegistry {
@@ -69,6 +74,18 @@
             registry.put(theClass, rules);
             assert registry.get(theClass) == rules;
             result = rules;
+
+            if (LogVerbose.getValue()) {
+                try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                    Debug.log("Match rules for %s", theClass.getSimpleName());
+                    for (Entry<Class<? extends ValueNode>, List<MatchStatement>> entry : result.entrySet()) {
+                        Debug.log("  For node class: %s", entry.getKey());
+                        for (MatchStatement statement : entry.getValue()) {
+                            Debug.log("    %s", statement.getPattern());
+                        }
+                    }
+                }
+            }
         }
 
         if (result.size() == 0) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java	Fri May 02 02:45:26 2014 +0200
@@ -28,7 +28,7 @@
  * The repeatable representation of {@link MatchRule}. Should never be used directly.
  */
 @Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
+@Target(ElementType.METHOD)
 public @interface MatchRules {
     MatchRule[] value();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Fri May 02 02:45:26 2014 +0200
@@ -22,12 +22,19 @@
  */
 package com.oracle.graal.compiler.match;
 
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
+
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode;
 import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -36,20 +43,34 @@
  */
 
 public class MatchStatement {
+    private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess");
+
+    /**
+     * A printable name for this statement. Usually it's just the name of the method doing the
+     * emission.
+     */
     private final String name;
+
+    /**
+     * The actual match pattern.
+     */
     private final MatchPattern pattern;
-    private final Class<? extends MatchGenerator> generatorClass;
+
+    /**
+     * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission.
+     */
+    private Method generatorMethod;
 
-    public MatchStatement(String name, MatchPattern pattern) {
+    /**
+     * The name of arguments in the order they are expected to be passed to the generator method.
+     */
+    private String[] arguments;
+
+    public MatchStatement(String name, MatchPattern pattern, Method generator, String[] arguments) {
         this.name = name;
         this.pattern = pattern;
-        this.generatorClass = null;
-    }
-
-    public MatchStatement(String name, MatchPattern pattern, Class<? extends MatchGenerator> generator) {
-        this.name = name;
-        this.pattern = pattern;
-        this.generatorClass = generator;
+        this.generatorMethod = generator;
+        this.arguments = arguments;
     }
 
     /**
@@ -61,37 +82,56 @@
      * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
      *         evaluated by the NodeLIRBuilder.
      */
-    public boolean generate(NodeLIRBuilder builder, ValueNode node, List<ScheduledNode> nodes) {
-        MatchContext context = new MatchContext(builder, this, node, nodes);
-        Result result = pattern.match(node, context);
-        if (result == Result.OK) {
-            result = context.validate();
+    public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List<ScheduledNode> nodes) {
+        assert index == nodes.indexOf(node);
+        // Check that the basic shape matches
+        Result result = pattern.matchShape(node, this);
+        if (result != Result.OK) {
+            return false;
         }
+        // Now ensure that the other safety constraints are matched.
+        MatchContext context = new MatchContext(builder, this, index, node, nodes);
+        result = pattern.matchUsage(node, context);
         if (result == Result.OK) {
-            MatchGenerator generator = null;
             try {
-                generator = generatorClass.newInstance();
-                // Transfer values into gen
-                context.transferState(generator);
-                ComplexMatchResult value = generator.match(builder);
+                // Invoke the generator method and set the result if it's non null.
+                ComplexMatchResult value = (ComplexMatchResult) generatorMethod.invoke(builder, buildArgList(context));
                 if (value != null) {
                     context.setResult(value);
+                    MatchStatementSuccess.increment();
                     return true;
                 }
-            } catch (InstantiationException | IllegalAccessException e) {
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                 throw new GraalInternalError(e);
             }
         } else {
-            // This is fairly verbose for normal usage.
-            // if (result.code != MatchResultCode.WRONG_CLASS) {
-            // // Don't bother logging if it's just the wrong shape.
-            // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id),
-            // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph());
-            // }
+            if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) {
+                Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result);
+            }
         }
         return false;
     }
 
+    /**
+     * @param context
+     * @return the ValueNodes captured by the match rule in the order expected by the
+     *         generatorMethod
+     */
+    private Object[] buildArgList(MatchContext context) {
+        Object[] result = new Object[arguments.length];
+        for (int i = 0; i < arguments.length; i++) {
+            if ("root".equals(arguments[i])) {
+                result[i] = context.getRoot();
+            } else {
+                result[i] = context.namedNode(arguments[i]);
+                if (result[i] == null) {
+                    throw new GraalGraphInternalError("Can't find named node %s", arguments[i]);
+                }
+            }
+        }
+        return result;
+    }
+
     public String formatMatch(ValueNode root) {
         return pattern.formatMatch(root);
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Fri May 02 02:45:26 2014 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * Describes the properties of a node for use when building a {@link MatchPattern}s.
+ * Describes the properties of a node for use when building a {@link MatchPattern}.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
@@ -39,13 +39,7 @@
      * if they were directly on the node being described but that may complicate the annotation
      * processing.
      */
-    Class<? extends ValueNode> value();
-
-    /**
-     * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed
-     * from the end.
-     */
-    String shortName() default "";
+    Class<? extends ValueNode> nodeClass();
 
     /**
      * The number of matchable inputs, which may be less than the real number of inputs.
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizationStub.java	Fri May 02 02:45:26 2014 +0200
@@ -35,7 +35,7 @@
 
     public AMD64DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(providers, target, linkage);
-        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14});
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Fri May 02 02:45:26 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri May 02 02:45:26 2014 +0200
@@ -312,7 +312,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Fri May 02 02:45:26 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Fri May 02 02:45:26 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -41,7 +42,7 @@
 @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
@@ -49,32 +50,51 @@
     @Alive(REG) AllocatableValue senderSp;
     @Alive(REG) AllocatableValue senderFp;
 
-    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc, AllocatableValue senderSp,
-                    AllocatableValue senderFp) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc,
+                    AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        final int totalFrameSize = crb.frameMap.totalFrameSize();
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+        final int totalFrameSize = frameMap.totalFrameSize();
+
+        // Push return address.
         masm.push(asRegister(framePc));
+
+        // Push base pointer.
         masm.push(asRegister(senderFp));
-        masm.movq(rbp, rsp);
+        masm.movq(rbp, stackPointerRegister);
 
         /*
          * Allocate a full sized frame. Since return address and base pointer are already in place
          * (see above) we allocate two words less.
          */
-        masm.decrementq(rsp, totalFrameSize - 2 * crb.target.wordSize);
+        masm.decrementq(stackPointerRegister, totalFrameSize - 2 * crb.target.wordSize);
+
+        // Save return registers after moving the frame.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize), integerResultRegister);
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize), floatResultRegister);
 
         // Set up last Java values.
-        masm.movq(new AMD64Address(thread, threadLastJavaSpOffset), rsp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaSpOffset), stackPointerRegister);
 
         /*
          * Save the PC since it cannot easily be retrieved using the last Java SP after we aligned
@@ -82,12 +102,12 @@
          * blob.
          */
         masm.leaq(rax, new AMD64Address(rip, 0));
-        masm.movq(new AMD64Address(thread, threadLastJavaPcOffset), rax);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaPcOffset), rax);
 
         // Use BP because the frames look interpreted now.
-        masm.movq(new AMD64Address(thread, threadLastJavaFpOffset), rbp);
+        masm.movq(new AMD64Address(threadRegister, threadLastJavaFpOffset), rbp);
 
         // Align the stack for the following unpackFrames call.
-        masm.andq(rsp, -(crb.target.stackAlignment));
+        masm.andq(stackPointerRegister, -(crb.target.stackAlignment));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 02 02:45:26 2014 +0200
@@ -26,10 +26,10 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.*;
 import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.*;
 import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.*;
@@ -63,7 +63,8 @@
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkage(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
-        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64DeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        link(new AMD64UncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
 
         // When the java.ext.dirs property is modified then the crypto classes might not be found.
         // If that's the case we ignore the ClassNotFoundException and continue since we cannot
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -41,6 +41,7 @@
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.data.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
@@ -189,8 +190,8 @@
         super.emitForeignCall(linkage, result, arguments, temps, info);
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        append(new AMD64HotSpotLeaveCurrentStackFrameOp());
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        append(new AMD64HotSpotLeaveCurrentStackFrameOp(saveRegisterOp));
     }
 
     public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
@@ -199,18 +200,18 @@
         append(new AMD64HotSpotLeaveDeoptimizedStackFrameOp(frameSizeVariable, initialInfoVariable));
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        Register thread = getProviders().getRegisters().getThreadRegister();
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
         Variable senderFpVariable = load(senderFp);
-        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
-                        senderSpVariable, senderFpVariable));
+        append(new AMD64HotSpotEnterUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), framePcVariable,
+                        senderSpVariable, senderFpVariable, saveRegisterOp));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
-        Register thread = getProviders().getRegisters().getThreadRegister();
-        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset()));
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        Register threadRegister = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotLeaveUnpackFramesStackFrameOp(threadRegister, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), saveRegisterOp));
     }
 
     /**
@@ -321,6 +322,21 @@
         return result;
     }
 
+    public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(DeoptimizationFetchUnrollInfoCallNode.FETCH_UNROLL_INFO);
+
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
+        Variable result = super.emitForeignCall(linkage, null, thread.asValue(Kind.Long));
+        append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+
+        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((AMD64HotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
+        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
+        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
+
+        return result;
+    }
+
     protected AMD64ZapRegistersOp emitZapRegisters(Register[] zappedRegisters, Constant[] zapValues) {
         AMD64ZapRegistersOp zap = new AMD64ZapRegistersOp(zappedRegisters, zapValues);
         append(zap);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Fri May 02 02:45:26 2014 +0200
@@ -24,19 +24,50 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops the current frame off the stack including the return address and restores the return
+ * registers stored on the stack.
  */
 @Opcode("LEAVE_CURRENT_STACK_FRAME")
 final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
 
+    private final SaveRegistersOp saveRegisterOp;
+
+    public AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) {
+        this.saveRegisterOp = saveRegisterOp;
+    }
+
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointer = registerConfig.getFrameRegister();
+
+        // Restore integer result register.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+        masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize));
+
+        // Restore float result register.
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
+
+        /*
+         * All of the register save area will be popped of the stack. Only the return address
+         * remains.
+         */
         leaveFrameAndRestoreRbp(crb, masm);
-        masm.addq(rsp, crb.target.arch.getReturnAddressSize());
+
+        // Remove return address.
+        masm.addq(stackPointer, crb.target.arch.getReturnAddressSize());
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Fri May 02 02:45:26 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,14 @@
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * Pops the current frame off the stack including the return address.
+ * Pops a deoptimized stack frame off the stack including the return address.
  */
 @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
 final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
@@ -47,9 +48,13 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        masm.addq(rsp, asRegister(frameSize));
-        // Restore the frame pointer before stack bang because if a stack overflow is thrown it
-        // needs to be pushed (and preserved).
+        Register stackPointer = crb.frameMap.registerConfig.getFrameRegister();
+        masm.addq(stackPointer, asRegister(frameSize));
+
+        /*
+         * Restore the frame pointer before stack bang because if a stack overflow is thrown it
+         * needs to be pushed (and preserved).
+         */
         masm.movq(rbp, asRegister(framePointer));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Fri May 02 02:45:26 2014 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.hotspot.amd64;
 
-import static com.oracle.graal.amd64.AMD64.*;
-
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
@@ -38,26 +38,42 @@
 @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
 
-    private final Register thread;
+    private final Register threadRegister;
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
     private final int threadLastJavaFpOffset;
 
-    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset) {
-        this.thread = thread;
+    private final SaveRegistersOp saveRegisterOp;
+
+    AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) {
+        this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.saveRegisterOp = saveRegisterOp;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig registerConfig = frameMap.registerConfig;
+        RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap);
+        Register stackPointerRegister = registerConfig.getFrameRegister();
+
         // Restore stack pointer.
-        masm.movq(rsp, new AMD64Address(thread, threadLastJavaSpOffset));
+        masm.movq(stackPointerRegister, new AMD64Address(threadRegister, threadLastJavaSpOffset));
 
         // Clear last Java frame values.
-        masm.movslq(new AMD64Address(thread, threadLastJavaSpOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaPcOffset), 0);
-        masm.movslq(new AMD64Address(thread, threadLastJavaFpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaSpOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaPcOffset), 0);
+        masm.movslq(new AMD64Address(threadRegister, threadLastJavaFpOffset), 0);
+
+        // Restore return values.
+        final int stackSlotSize = frameMap.stackSlotSize();
+        Register integerResultRegister = registerConfig.getReturnRegister(Kind.Long);
+        masm.movptr(integerResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize));
+
+        Register floatResultRegister = registerConfig.getReturnRegister(Kind.Double);
+        masm.movdbl(floatResultRegister, new AMD64Address(stackPointerRegister, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize));
     }
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri May 02 02:45:26 2014 +0200
@@ -244,39 +244,17 @@
         setResult(x, result);
     }
 
-    /**
-     * Helper class to convert the NodeLIRBuilder into the current subclass.
-     */
-    static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator {
-        public AMD64HotSpotMatchGenerator() {
-        }
-
-        public ComplexMatchResult match(NodeLIRBuilder gen) {
-            return match((AMD64HotSpotNodeLIRBuilder) gen);
-        }
-
-        abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen);
-    }
-
     @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))")
     @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))")
     @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))")
     @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))")
-    public static class IfCompareMemory extends AMD64HotSpotMatchGenerator {
-        IfNode root;
-        Access access;
-        ValueNode value;
-        CompareNode compare;
-
-        @Override
-        public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) {
-            if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
-                return builder -> {
-                    gen.emitCompareCompressedMemory(root, value, access, compare);
-                    return null;
-                };
-            }
-            return null;
+    public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
+            return builder -> {
+                emitCompareCompressedMemory(root, value, access, compare);
+                return null;
+            };
         }
+        return null;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64UncommonTrapStub.java	Fri May 02 02:45:26 2014 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.graal.hotspot.amd64;
+
+import static com.oracle.graal.amd64.AMD64.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
+
+final class AMD64UncommonTrapStub extends UncommonTrapStub {
+
+    private RegisterConfig registerConfig;
+
+    public AMD64UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        Register[] allocatable = new Register[]{rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r13, r14};
+        registerConfig = new AMD64HotSpotRegisterConfig(target.arch, HotSpotGraalRuntime.runtime().getConfig(), allocatable);
+    }
+
+    @Override
+    public RegisterConfig getRegisterConfig() {
+        return registerConfig;
+    }
+}
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -281,31 +281,8 @@
         return result;
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotLIRGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -72,31 +72,8 @@
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitLeaveCurrentStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public void emitLeaveUnpackFramesStackFrame() {
-        throw GraalInternalError.unimplemented();
-    }
-
     public SaveRegistersOp emitSaveAllRegisters() {
         throw GraalInternalError.unimplemented();
     }
 
-    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
-        throw GraalInternalError.unimplemented();
-    }
-
-    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
-        throw GraalInternalError.unimplemented();
-    }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Fri May 02 02:45:26 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri May 02 02:45:26 2014 +0200
@@ -232,7 +232,7 @@
             MarkId.recordMark(crb, MarkId.EXCEPTION_HANDLER_ENTRY);
             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             MarkId.recordMark(crb, MarkId.DEOPT_HANDLER_ENTRY);
-            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Fri May 02 02:45:26 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 02 02:45:26 2014 +0200
@@ -24,10 +24,10 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.sparc.SPARC.*;
 
 import com.oracle.graal.api.code.*;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -300,7 +300,7 @@
         return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
     }
 
-    public void emitLeaveCurrentStackFrame() {
+    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
         append(new SPARCHotSpotLeaveCurrentStackFrameOp());
     }
 
@@ -308,7 +308,7 @@
         append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
     }
 
-    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp) {
+    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
         Register thread = getProviders().getRegisters().getThreadRegister();
         Variable framePcVariable = load(framePc);
         Variable senderSpVariable = load(senderSp);
@@ -316,7 +316,7 @@
         append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable));
     }
 
-    public void emitLeaveUnpackFramesStackFrame() {
+    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
         Register thread = getProviders().getRegisters().getThreadRegister();
         append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 02 02:45:26 2014 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.phases.common.InliningUtil.*;
@@ -117,11 +118,23 @@
      */
     private final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
 
-    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking) {
+    /**
+     * The address of the native CompileTask associated with this compilation. If 0L, then this
+     * compilation is being managed by a Graal compilation queue otherwise its managed by a native
+     * HotSpot compilation queue.
+     */
+    private final long ctask;
+
+    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, boolean blocking) {
         this.backend = backend;
         this.method = method;
         this.entryBCI = entryBCI;
-        this.id = method.allocateCompileId(entryBCI);
+        if (ctask == 0L) {
+            this.id = method.allocateCompileId(entryBCI);
+        } else {
+            this.id = unsafe.getInt(ctask + backend.getRuntime().getConfig().compileTaskCompileIdOffset);
+        }
+        this.ctask = ctask;
         this.blocking = blocking;
         this.taskId = uniqueTaskIds.incrementAndGet();
         this.status = new AtomicReference<>(CompilationStatus.Queued);
@@ -337,13 +350,17 @@
                 System.exit(-1);
             }
         } finally {
+            int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+            if (ctask != 0L) {
+                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
+            }
             if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) {
-                long processedBytes = InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes;
+
                 long time = CompilationTime.getCurrentValue() - previousCompilationTime;
                 TimeUnit timeUnit = CompilationTime.getTimeUnit();
                 long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
                 CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
-                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, (int) processedBytes, time, timeUnitsPerSecond, installedCode);
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
             }
 
             if (clearFromCompilationQueue) {
@@ -388,7 +405,7 @@
         final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache();
         InstalledCode installedCode = null;
         try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) {
-            installedCode = codeCache.installMethod(method, compResult);
+            installedCode = codeCache.installMethod(method, compResult, ctask);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Fri May 02 02:45:26 2014 +0200
@@ -317,7 +317,7 @@
     class CTWCompilationTask extends CompilationTask {
 
         CTWCompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method) {
-            super(backend, method, INVOCATION_ENTRY_BCI, false);
+            super(backend, method, INVOCATION_ENTRY_BCI, 0L, false);
         }
 
         /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri May 02 02:45:26 2014 +0200
@@ -45,11 +45,6 @@
 public abstract class HotSpotBackend extends Backend {
 
     /**
-     * Descriptor for {@link DeoptimizationStub}.
-     */
-    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
-
-    /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
      * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a
      * compiled method.
@@ -57,11 +52,6 @@
     public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class);
 
     /**
-     * Descriptor for SharedRuntime::deopt_blob()-&gt;unpack().
-     */
-    public static final ForeignCallDescriptor DEOPT_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
-
-    /**
      * Descriptor for SharedRuntime::get_ic_miss_stub().
      */
     public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Fri May 02 02:45:26 2014 +0200
@@ -34,11 +34,17 @@
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
+    public final long ctask;
 
     public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+        this(target, method, compResult, 0L);
+    }
+
+    public HotSpotCompiledNmethod(TargetDescription target, HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         super(target, compResult);
         this.method = method;
         this.entryBCI = compResult.getEntryBCI();
         this.id = compResult.getId();
+        this.ctask = ctask;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Fri May 02 02:45:26 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
-import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CompilationResult.Call;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Fri May 02 02:45:26 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -39,6 +40,16 @@
 public abstract class HotSpotHostBackend extends HotSpotBackend implements HostBackend {
 
     /**
+     * Descriptor for {@link DeoptimizationStub#deoptimizationHandler}.
+     */
+    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptimizationHandler", void.class);
+
+    /**
+     * Descriptor for {@link UncommonTrapStub#uncommonTrapHandler}.
+     */
+    public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
+
+    /**
      * This will be 0 if stack banging is disabled.
      */
     protected final int pagesToBang;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -24,8 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.gen.*;
 
@@ -43,21 +45,87 @@
      */
     void emitTailcall(Value[] args, Value address);
 
-    void emitLeaveCurrentStackFrame();
-
-    void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo);
+    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
 
-    void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp);
-
-    void emitLeaveUnpackFramesStackFrame();
-
+    /**
+     * Emits code for a {@link SaveAllRegistersNode}.
+     *
+     * @return a {@link SaveRegistersOp} operation
+     */
     SaveRegistersOp emitSaveAllRegisters();
 
-    void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason);
+    /**
+     * Emits code for a {@link LeaveCurrentStackFrameNode}.
+     *
+     * @param saveRegisterOp saved registers
+     */
+    default void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link LeaveDeoptimizedStackFrameNode}.
+     *
+     * @param frameSize
+     * @param initialInfo
+     */
+    default void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link EnterUnpackFramesStackFrameNode}.
+     *
+     * @param framePc
+     * @param senderSp
+     * @param senderFp
+     * @param saveRegisterOp
+     */
+    default void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo);
+    /**
+     * Emits code for a {@link LeaveUnpackFramesStackFrameNode}.
+     *
+     * @param saveRegisterOp
+     */
+    default void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link PushInterpreterFrameNode}.
+     *
+     * @param frameSize
+     * @param framePc
+     * @param senderSp
+     * @param initialInfo
+     */
+    default void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
+        throw GraalInternalError.unimplemented();
+    }
 
-    Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp);
+    /**
+     * Emits code for a {@link UncommonTrapCallNode}.
+     *
+     * @param trapRequest
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
+
+    /**
+     * Emits code for a {@link DeoptimizationFetchUnrollInfoCallNode}.
+     *
+     * @param saveRegisterOp
+     * @return a {@code Deoptimization::UnrollBlock} pointer
+     */
+    default Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
+        throw GraalInternalError.unimplemented();
+    }
 
     /**
      * Gets a stack slot for a lock at a given lock nesting depth.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri May 02 02:45:26 2014 +0200
@@ -170,7 +170,7 @@
                 String name = annotation.name();
                 Flags.Flag entry = flags.get(name);
                 if (entry == null) {
-                    if (!isRequired(currentArch, annotation.archs())) {
+                    if (annotation.optional() || !isRequired(currentArch, annotation.archs())) {
                         continue;
                     }
                     throw new IllegalArgumentException("flag not found: " + name);
@@ -716,6 +716,7 @@
     @HotSpotVMFlag(name = "CIPrintCompilerName") @Stable public boolean printCompilerName;
     @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining;
     @HotSpotVMFlag(name = "GraalUseFastLocking") @Stable public boolean useFastLocking;
+    @HotSpotVMFlag(name = "UseGraalCompilationQueue", optional = true) @Stable public boolean useGraalCompilationQueue;
     @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable;
     @HotSpotVMFlag(name = "GPUOffload") @Stable public boolean gpuOffload;
     @HotSpotVMFlag(name = "TieredCompilation") @Stable public boolean tieredCompilation;
@@ -1067,6 +1068,9 @@
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
 
+    @HotSpotVMField(name = "CompileTask::_compile_id", type = "uint", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskCompileIdOffset;
+    @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset;
+
     /**
      * Value of Method::extra_stack_entries().
      */
@@ -1353,8 +1357,6 @@
         return unsafe.getAddress(codeCacheHeap + codeHeapMemoryOffset + virtualSpaceHighBoundaryOffset);
     }
 
-    @Stable public long handleDeoptStub;
-
     @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub;
     @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMFlag.java	Fri May 02 02:45:26 2014 +0200
@@ -36,4 +36,6 @@
      * required on all architectures.
      */
     String[] archs() default {};
+
+    boolean optional() default false;
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java	Fri May 02 02:45:26 2014 +0200
@@ -33,8 +33,10 @@
     /**
      * Compiles a method to machine code. This method is called from the VM
      * (VMToCompiler::compileMethod).
+     *
+     * @param ctask the CompileTask pointer if this is a request from a HotSpot compiler thread
      */
-    void compileMethod(long metaspaceMethod, int entryBCI, boolean blocking);
+    void compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking);
 
     void shutdownCompiler() throws Exception;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 02 02:45:26 2014 +0200
@@ -192,55 +192,57 @@
             }
         }
 
-        // Create compilation queue.
-        CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
-            public GraalDebugConfig getDebugConfig() {
-                return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
-            }
-        });
-        compileQueue = new Queue(factory);
+        if (runtime.getConfig().useGraalCompilationQueue) {
+
+            // Create compilation queue.
+            CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() {
+                public GraalDebugConfig getDebugConfig() {
+                    return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null;
+                }
+            });
+            compileQueue = new Queue(factory);
 
-        // Create queue status printing thread.
-        if (PrintQueue.getValue()) {
-            Thread t = new Thread() {
+            // Create queue status printing thread.
+            if (PrintQueue.getValue()) {
+                Thread t = new Thread() {
 
-                @Override
-                public void run() {
-                    while (true) {
-                        TTY.println(compileQueue.toString());
-                        try {
-                            Thread.sleep(1000);
-                        } catch (InterruptedException e) {
+                    @Override
+                    public void run() {
+                        while (true) {
+                            TTY.println(compileQueue.toString());
+                            try {
+                                Thread.sleep(1000);
+                            } catch (InterruptedException e) {
+                            }
                         }
                     }
-                }
-            };
-            t.setDaemon(true);
-            t.start();
-        }
-
-        if (PrintCompRate.getValue() != 0) {
-            if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
-                throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
+                };
+                t.setDaemon(true);
+                t.start();
             }
-            Thread t = new Thread() {
+
+            if (PrintCompRate.getValue() != 0) {
+                if (runtime.getConfig().ciTime || runtime.getConfig().ciTimeEach) {
+                    throw new GraalInternalError("PrintCompRate is incompatible with CITime and CITimeEach");
+                }
+                Thread t = new Thread() {
 
-                @Override
-                public void run() {
-                    while (true) {
-                        runtime.getCompilerToVM().printCompilationStatistics(true, false);
-                        runtime.getCompilerToVM().resetCompilationStatistics();
-                        try {
-                            Thread.sleep(PrintCompRate.getValue());
-                        } catch (InterruptedException e) {
+                    @Override
+                    public void run() {
+                        while (true) {
+                            runtime.getCompilerToVM().printCompilationStatistics(true, false);
+                            runtime.getCompilerToVM().resetCompilationStatistics();
+                            try {
+                                Thread.sleep(PrintCompRate.getValue());
+                            } catch (InterruptedException e) {
+                            }
                         }
                     }
-                }
-            };
-            t.setDaemon(true);
-            t.start();
+                };
+                t.setDaemon(true);
+                t.start();
+            }
         }
-
         BenchmarkCounters.initialize(runtime.getCompilerToVM());
 
         compilerStartTime = System.nanoTime();
@@ -346,23 +348,24 @@
     private void enqueue(Method m) throws Throwable {
         JavaMethod javaMethod = runtime.getHostProviders().getMetaAccess().lookupJavaMethod(m);
         assert !((HotSpotResolvedJavaMethod) javaMethod).isAbstract() && !((HotSpotResolvedJavaMethod) javaMethod).isNative() : javaMethod;
-        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, false);
+        compileMethod((HotSpotResolvedJavaMethod) javaMethod, StructuredGraph.INVOCATION_ENTRY_BCI, 0L, false);
     }
 
     public void shutdownCompiler() throws Exception {
-        try (Enqueueing enqueueing = new Enqueueing()) {
-            // We have to use a privileged action here because shutting down the compiler might be
-            // called from user code which very likely contains unprivileged frames.
-            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
-                public Void run() throws Exception {
-                    if (compileQueue != null) {
-                        compileQueue.shutdown();
+        if (runtime.getConfig().useGraalCompilationQueue) {
+            try (Enqueueing enqueueing = new Enqueueing()) {
+                // We have to use a privileged action here because shutting down the compiler might
+                // be called from user code which very likely contains unprivileged frames.
+                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws Exception {
+                        if (compileQueue != null) {
+                            compileQueue.shutdown();
+                        }
+                        return null;
                     }
-                    return null;
-                }
-            });
+                });
+            }
         }
-
         printDebugValues(ResetDebugValuesAfterBootstrap.getValue() ? "application" : null, false);
         phaseTransition("final");
 
@@ -537,22 +540,34 @@
     }
 
     @Override
-    public void compileMethod(long metaspaceMethod, final int entryBCI, final boolean blocking) {
+    public void compileMethod(long metaspaceMethod, final int entryBCI, long ctask, final boolean blocking) {
         final HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
-        // We have to use a privileged action here because compilations are enqueued from user code
-        // which very likely contains unprivileged frames.
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-            public Void run() {
-                compileMethod(method, entryBCI, blocking);
-                return null;
-            }
-        });
+        if (ctask != 0L) {
+            // This is on a VM CompilerThread - no user frames exist
+            compileMethod(method, entryBCI, ctask, false);
+        } else {
+            // We have to use a privileged action here because compilations are
+            // enqueued from user code which very likely contains unprivileged frames.
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    compileMethod(method, entryBCI, 0L, blocking);
+                    return null;
+                }
+            });
+        }
     }
 
     /**
      * Compiles a method to machine code.
      */
-    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, final boolean blocking) {
+    void compileMethod(final HotSpotResolvedJavaMethod method, final int entryBCI, long ctask, final boolean blocking) {
+        if (ctask != 0L) {
+            HotSpotBackend backend = runtime.getHostBackend();
+            CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, false);
+            task.runCompilation(false);
+            return;
+        }
+
         boolean osrCompilation = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
         if (osrCompilation && bootstrapRunning) {
             // no OSR compilations during bootstrap - the compiler is just too slow at this point,
@@ -575,7 +590,7 @@
                 assert method.isQueuedForCompilation();
 
                 HotSpotBackend backend = runtime.getHostBackend();
-                CompilationTask task = new CompilationTask(backend, method, entryBCI, block);
+                CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, block);
 
                 try {
                     compileQueue.execute(task);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Fri May 02 02:45:26 2014 +0200
@@ -206,12 +206,12 @@
         return installedCode;
     }
 
-    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) {
+    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
         if (compResult.getId() == -1) {
             compResult.setId(method.allocateCompileId(compResult.getEntryBCI()));
         }
         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), true);
-        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult), installedCode, method.getSpeculationLog());
+        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(target, method, compResult, ctask), installedCode, method.getSpeculationLog());
         return logOrDump(installedCode, compResult);
     }
 
@@ -236,7 +236,7 @@
     @Override
     public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) {
         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
-        return installMethod(hotspotMethod, compResult);
+        return installMethod(hotspotMethod, compResult, 0L);
     }
 
     public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 02 02:45:26 2014 +0200
@@ -103,7 +103,6 @@
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
-        registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
         registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Fri May 02 02:45:26 2014 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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.graal.hotspot.nodes;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * A call to the runtime code {@code Deoptimization::fetch_unroll_info}.
+ */
+@NodeInfo(allowedUsageTypes = {InputType.Memory})
+public class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+
+    @Input private SaveAllRegistersNode registerSaver;
+    private final ForeignCallsProvider foreignCalls;
+    public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, Word.class);
+
+    public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) {
+        super(StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public LocationIdentity[] getLocationIdentities() {
+        return foreignCalls.getKilledLocations(FETCH_UNROLL_INFO);
+    }
+
+    public SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitDeoptimizationFetchUnrollInfoCall(getSaveRegistersOp());
+        gen.setResult(this, result);
+    }
+
+    @NodeIntrinsic
+    public static native Word fetchUnrollInfo(long registerSaver);
+
+    public MemoryCheckpoint asMemoryCheckpoint() {
+        return null;
+    }
+
+    public MemoryPhiNode asMemoryPhi() {
+        return null;
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Fri May 02 02:45:26 2014 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.word.*;
@@ -39,12 +40,18 @@
     @Input private ValueNode framePc;
     @Input private ValueNode senderSp;
     @Input private ValueNode senderFp;
+    @Input private SaveAllRegistersNode registerSaver;
 
-    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp) {
+    public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) {
         super(StampFactory.forVoid());
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
@@ -52,9 +59,9 @@
         Value operandValue = gen.operand(framePc);
         Value senderSpValue = gen.operand(senderSp);
         Value senderFpValue = gen.operand(senderFp);
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue);
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitEnterUnpackFramesStackFrame(operandValue, senderSpValue, senderFpValue, getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp);
+    public static native void enterUnpackFramesStackFrame(Word framePc, Word senderSp, Word senderFp, long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Fri May 02 02:45:26 2014 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.nodes.*;
 
-@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
+@MatchableNode(nodeClass = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
 public class HotSpotMatchableNodes {
     public static class CompressionNodeAdapter extends MatchNodeAdapter {
         @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Fri May 02 02:45:26 2014 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -33,15 +34,22 @@
  */
 public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveCurrentStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveCurrentStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveCurrentStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveCurrentStackFrame();
+    public static native void leaveCurrentStackFrame(long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Fri May 02 02:45:26 2014 +0200
@@ -25,6 +25,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -34,15 +35,22 @@
  */
 public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
-    public LeaveUnpackFramesStackFrameNode() {
+    @Input private SaveAllRegistersNode registerSaver;
+
+    public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) {
         super(StampFactory.forVoid());
+        this.registerSaver = (SaveAllRegistersNode) registerSaver;
+    }
+
+    private SaveRegistersOp getSaveRegistersOp() {
+        return registerSaver.getSaveRegistersOp();
     }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame();
+        ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLeaveUnpackFramesStackFrame(getSaveRegistersOp());
     }
 
     @NodeIntrinsic
-    public static native void leaveUnpackFramesStackFrame();
+    public static native void leaveUnpackFramesStackFrame(long registerSaver);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Fri May 02 02:45:26 2014 +0200
@@ -45,30 +45,35 @@
  *
  * The steps taken by this frame are as follows:
  *
- * - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all potentially
- * live registers (at a pollpoint many registers can be live).
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
  *
- * - call the C routine: Deoptimization::fetch_unroll_info (this function returns information about
- * the number and size of interpreter frames which are equivalent to the frame which is being
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
  * deoptimized)
  *
- * - deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
  * be captured in the vframeArray as needed.
  *
- * - deallocate the deoptimization frame
+ * <li>deallocate the deoptimization frame
  *
- * - in a loop using the information returned in the previous step push new interpreter frames (take
- * care to propagate the return values through each new frame pushed)
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
  *
- * - create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
  *
- * - call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
  * interpreter frame which was just created)
  *
- * - deallocate the dummy unpack_frame
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
  *
- * - ensure that all the return values are correctly set and then do a return to the interpreter
- * entry point
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
  */
 public class DeoptimizationStub extends SnippetStub {
 
@@ -97,31 +102,15 @@
     }
 
     /**
-     * Uncommon trap.
-     *
-     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
-     * routine captures the return values and returns a structure which describes the current frame
-     * size and the sizes of all replacement frames. The current frame is compiled code and may
-     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
-     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
-     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
-     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
-     * was patched.
-     *
-     * <p>
-     * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
-     * because we change the current stack layout and so the code is very sensitive to register
-     * allocation.</b>
+     * Deoptimization handler for normal deoptimization
+     * {@link HotSpotVMConfig#deoptimizationUnpackDeopt}.
      */
     @Snippet
-    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+    private static void deoptimizationHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
         final Word thread = registerAsWord(threadRegister);
-        long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
 
-        final int actionAndReason = readPendingDeoptimization(thread);
-        writePendingDeoptimization(thread, -1);
-
-        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+        final Word unrollBlock = DeoptimizationFetchUnrollInfoCallNode.fetchUnrollInfo(registerSaver);
 
         // Pop all the frames we must move/replace.
         //
@@ -131,7 +120,7 @@
         // 3: caller of deoptimizing frame (could be compiled/interpreted).
 
         // Pop self-frame.
-        LeaveCurrentStackFrameNode.leaveCurrentStackFrame();
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
 
         // Load the initial info we should save (e.g. frame pointer).
         final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
@@ -193,13 +182,13 @@
          * unknown alignment we need to align it here before calling C++ code.
          */
         final Word senderFp = initialInfo;
-        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp);
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
 
-        // Pass uncommon trap mode to unpack frames.
-        final int mode = deoptimizationUnpackUncommonTrap();
+        // Pass unpack deopt mode to unpack frames.
+        final int mode = deoptimizationUnpackDeopt();
         unpackFrames(UNPACK_FRAMES, thread, mode);
 
-        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame();
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Fri May 02 02:45:26 2014 +0200
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.stubs;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.StubUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Uncommon trap stub.
+ *
+ * This is the entry point for code which is returning to a de-optimized frame.
+ *
+ * The steps taken by this frame are as follows:
+ *
+ * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all
+ * potentially live registers (at a pollpoint many registers can be live).
+ *
+ * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information
+ * about the number and size of interpreter frames which are equivalent to the frame which is being
+ * deoptimized)
+ *
+ * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now
+ * be captured in the vframeArray as needed.
+ *
+ * <li>deallocate the deoptimization frame
+ *
+ * <li>in a loop using the information returned in the previous step push new interpreter frames
+ * (take care to propagate the return values through each new frame pushed)
+ *
+ * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0)
+ *
+ * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the
+ * interpreter frame which was just created)
+ *
+ * <li>deallocate the dummy unpack_frame
+ *
+ * <li>ensure that all the return values are correctly set and then do a return to the interpreter
+ * entry point
+ *
+ * <p>
+ * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet
+ * because we change the current stack layout and so the code is very sensitive to register
+ * allocation.</b>
+ */
+public class UncommonTrapStub extends SnippetStub {
+
+    private final TargetDescription target;
+
+    public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
+        super(providers, target, linkage);
+        this.target = target;
+    }
+
+    @Override
+    public boolean preservesRegisters() {
+        return false;
+    }
+
+    @Override
+    protected Object getConstantParameterValue(int index, String name) {
+        switch (index) {
+            case 0:
+                return providers.getRegisters().getThreadRegister();
+            case 1:
+                return providers.getRegisters().getStackPointerRegister();
+            default:
+                throw GraalInternalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
+        }
+    }
+
+    /**
+     * Uncommon trap handler.
+     *
+     * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This
+     * routine captures the return values and returns a structure which describes the current frame
+     * size and the sizes of all replacement frames. The current frame is compiled code and may
+     * contain many inlined functions, each with their own JVM state. We pop the current frame, then
+     * push all the new frames. Then we call the C routine unpack_frames() to populate these frames.
+     * Finally unpack_frames() returns us the new target address. Notice that callee-save registers
+     * are BLOWN here; they have already been captured in the vframeArray at the time the return PC
+     * was patched.
+     */
+    @Snippet
+    private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) {
+        final Word thread = registerAsWord(threadRegister);
+        final long registerSaver = SaveAllRegistersNode.saveAllRegisters();
+
+        final int actionAndReason = readPendingDeoptimization(thread);
+        writePendingDeoptimization(thread, -1);
+
+        final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason);
+
+        // Pop all the frames we must move/replace.
+        //
+        // Frame picture (youngest to oldest)
+        // 1: self-frame
+        // 2: deoptimizing frame
+        // 3: caller of deoptimizing frame (could be compiled/interpreted).
+
+        // Pop self-frame.
+        LeaveCurrentStackFrameNode.leaveCurrentStackFrame(registerSaver);
+
+        // Load the initial info we should save (e.g. frame pointer).
+        final Word initialInfo = unrollBlock.readWord(deoptimizationUnrollBlockInitialInfoOffset());
+
+        // Pop deoptimized frame.
+        final int sizeOfDeoptimizedFrame = unrollBlock.readInt(deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset());
+        LeaveDeoptimizedStackFrameNode.leaveDeoptimizedStackFrame(sizeOfDeoptimizedFrame, initialInfo);
+
+        /*
+         * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
+         * total size of the interpreter frames plus shadow page size. Bang one page at a time
+         * because large sizes can bang beyond yellow and red zones.
+         * 
+         * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
+         */
+        final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
+        final int bangPages = NumUtil.roundUp(totalFrameSizes, pageSize()) / pageSize() + stackShadowPages();
+        Word stackPointer = readRegister(stackPointerRegister);
+
+        for (int i = 1; i < bangPages; i++) {
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0);
+        }
+
+        // Load number of interpreter frames.
+        final int numberOfFrames = unrollBlock.readInt(deoptimizationUnrollBlockNumberOfFramesOffset());
+
+        // Load address of array of frame sizes.
+        final Word frameSizes = unrollBlock.readWord(deoptimizationUnrollBlockFrameSizesOffset());
+
+        // Load address of array of frame PCs.
+        final Word framePcs = unrollBlock.readWord(deoptimizationUnrollBlockFramePcsOffset());
+
+        /*
+         * Get the current stack pointer (sender's original SP) before adjustment so that we can
+         * save it in the skeletal interpreter frame.
+         */
+        Word senderSp = readRegister(stackPointerRegister);
+
+        // Adjust old interpreter frame to make space for new frame's extra Java locals.
+        final int callerAdjustment = unrollBlock.readInt(deoptimizationUnrollBlockCallerAdjustmentOffset());
+        writeRegister(stackPointerRegister, readRegister(stackPointerRegister).subtract(callerAdjustment));
+
+        for (int i = 0; i < numberOfFrames; i++) {
+            final Word frameSize = frameSizes.readWord(i * wordSize());
+            final Word framePc = framePcs.readWord(i * wordSize());
+
+            // Push an interpreter frame onto the stack.
+            PushInterpreterFrameNode.pushInterpreterFrame(frameSize, framePc, senderSp, initialInfo);
+
+            // Get the current stack pointer (sender SP) and pass it to next frame.
+            senderSp = readRegister(stackPointerRegister);
+        }
+
+        // Get final return address.
+        final Word framePc = framePcs.readWord(numberOfFrames * wordSize());
+
+        /*
+         * Enter a frame to call out to unpack frames. Since we changed the stack pointer to an
+         * unknown alignment we need to align it here before calling C++ code.
+         */
+        final Word senderFp = initialInfo;
+        EnterUnpackFramesStackFrameNode.enterUnpackFramesStackFrame(framePc, senderSp, senderFp, registerSaver);
+
+        // Pass uncommon trap mode to unpack frames.
+        final int mode = deoptimizationUnpackUncommonTrap();
+        unpackFrames(UNPACK_FRAMES, thread, mode);
+
+        LeaveUnpackFramesStackFrameNode.leaveUnpackFramesStackFrame(registerSaver);
+    }
+
+    /**
+     * Reads the value of the passed register as a Word.
+     */
+    private static Word readRegister(Register register) {
+        return registerAsWord(register, false, false);
+    }
+
+    /**
+     * Writes the value of the passed register.
+     *
+     * @param value value the register should be set to
+     */
+    private static void writeRegister(Register register, Word value) {
+        writeRegisterAsWord(register, value);
+    }
+
+    @Fold
+    private static int stackShadowPages() {
+        return config().useStackBanging ? config().stackShadowPages : 0;
+    }
+
+    /**
+     * Returns the stack bias for the host architecture.
+     *
+     * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository.
+     *
+     * @return stack bias
+     */
+    @Deprecated
+    @Fold
+    private static int stackBias() {
+        return config().stackBias;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset() {
+        return config().deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockCallerAdjustmentOffset() {
+        return config().deoptimizationUnrollBlockCallerAdjustmentOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockNumberOfFramesOffset() {
+        return config().deoptimizationUnrollBlockNumberOfFramesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockTotalFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockTotalFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFrameSizesOffset() {
+        return config().deoptimizationUnrollBlockFrameSizesOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockFramePcsOffset() {
+        return config().deoptimizationUnrollBlockFramePcsOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnrollBlockInitialInfoOffset() {
+        return config().deoptimizationUnrollBlockInitialInfoOffset;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackDeopt() {
+        return config().deoptimizationUnpackDeopt;
+    }
+
+    @Fold
+    private static int deoptimizationUnpackUncommonTrap() {
+        return config().deoptimizationUnpackUncommonTrap;
+    }
+
+    public static final ForeignCallDescriptor UNPACK_FRAMES = descriptorFor(UncommonTrapStub.class, "unpackFrames");
+
+    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri May 02 02:45:26 2014 +0200
@@ -497,7 +497,7 @@
                     break;
                 case IROR:
                     assert asIntReg(src).equals(AMD64.rcx);
-                    masm.roll(asIntReg(dst));
+                    masm.rorl(asIntReg(dst));
                     break;
 
                 case LADD:
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri May 02 02:45:26 2014 +0200
@@ -113,6 +113,15 @@
     }
 
     /**
+     * Gets the size of a stack slot.
+     *
+     * @return stack slot size
+     */
+    public int stackSlotSize() {
+        return target.wordSize;
+    }
+
+    /**
      * Gets the frame size of the compiled frame, not including the size of the
      * {@link Architecture#getReturnAddressSize() return address slot}.
      *
@@ -208,8 +217,8 @@
      * @return the index of the stack slot
      */
     public int indexForStackSlot(StackSlot slot) {
-        assert offsetForStackSlot(slot) % target.wordSize == 0;
-        return offsetForStackSlot(slot) / target.wordSize;
+        assert offsetForStackSlot(slot) % stackSlotSize() == 0;
+        return offsetForStackSlot(slot) / stackSlotSize();
     }
 
     /**
@@ -259,7 +268,7 @@
      * @param kind the {@link PlatformKind} to be stored in the spill slot.
      * @return the size in bytes
      */
-    protected int spillSlotSize(PlatformKind kind) {
+    public int spillSlotSize(PlatformKind kind) {
         return target.getSizeInBytes(kind);
     }
 
@@ -321,7 +330,7 @@
         if (slots == 0) {
             return null;
         }
-        spillSize += (slots * target.wordSize);
+        spillSize += (slots * stackSlotSize());
 
         if (!objects.isEmpty()) {
             assert objects.length() <= slots;
@@ -329,7 +338,7 @@
             for (int slotIndex = 0; slotIndex < slots; slotIndex++) {
                 StackSlot objectSlot = null;
                 if (objects.get(slotIndex)) {
-                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * target.wordSize);
+                    objectSlot = allocateNewSpillSlot(Kind.Object, slotIndex * stackSlotSize());
                     objectStackSlots.add(objectSlot);
                     if (outObjectStackSlots != null) {
                         outObjectStackSlots.add(objectSlot);
@@ -352,7 +361,7 @@
     }
 
     public ReferenceMap initReferenceMap(boolean hasRegisters) {
-        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / target.wordSize);
+        ReferenceMap refMap = target.createReferenceMap(hasRegisters, frameSize() / stackSlotSize());
         for (StackSlot slot : objectStackSlots) {
             setReference(slot, refMap);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri May 02 02:45:26 2014 +0200
@@ -74,6 +74,9 @@
         if (stamp() == StampFactory.forNodeIntrinsic()) {
             return false;
         }
+        if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
+            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
+        }
         return updateStamp(stamp().join(object().stamp()));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri May 02 02:45:26 2014 +0200
@@ -60,21 +60,30 @@
     }
 
     @Override
-    public boolean inferStamp() {
-        if (stamp() instanceof ObjectStamp && object.stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object.stamp()).castTo((ObjectStamp) stamp()));
-        }
-        return updateStamp(object.stamp().join(stamp()));
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         assert getKind() == Kind.Object && object.getKind() == Kind.Object;
-        if (stamp().equals(object.stamp())) {
-            return object;
-        } else {
+
+        ObjectStamp my = (ObjectStamp) stamp();
+        ObjectStamp other = (ObjectStamp) object.stamp();
+
+        if (my.type() == null || other.type() == null) {
+            return this;
+        }
+        if (my.isExactType() && !other.isExactType()) {
             return this;
         }
+        if (my.nonNull() && !other.nonNull()) {
+            return this;
+        }
+        if (!my.type().isAssignableFrom(other.type())) {
+            return this;
+        }
+        /*
+         * The unsafe cast does not add any new type information, so it can be removed. Note that
+         * this means that the unsafe cast cannot be used to "drop" type information (in which case
+         * it must not be canonicalized in any case).
+         */
+        return object;
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri May 02 02:45:26 2014 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.truffle.api.*;
 
@@ -62,7 +61,7 @@
             }
             Stamp stamp = StampFactory.declared(lookupJavaType, nonNullArgument.asConstant().asInt() != 0);
             ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
-            UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, stamp, valueAnchorNode));
+            PiNode piCast = graph().unique(new PiNode(objectArgument, stamp, valueAnchorNode));
             this.replaceAtUsages(piCast);
             return valueAnchorNode;
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Fri May 02 02:45:26 2014 +0200
@@ -49,12 +49,12 @@
     /**
      * Gets access to AST instrumentation services.
      */
-    Instrumentation instrumentation();
+    Instrumentation getInstrumentation();
 
     /**
      * Access to information visualization services for the specific language.
      */
-    Visualizer visualizer();
+    Visualizer getVisualizer();
 
     /**
      * Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Fri May 02 02:45:26 2014 +0200
@@ -44,11 +44,11 @@
         return sourceManager;
     }
 
-    public final Instrumentation instrumentation() {
+    public final Instrumentation getInstrumentation() {
         return instrumentation;
     }
 
-    public Visualizer visualizer() {
+    public Visualizer getVisualizer() {
         return visualizer;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 02 02:45:26 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,17 +24,103 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+
 /**
  * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the
- * instrument is attached.
+ * instrument is attached, for the benefit of associated <em>tools</em>.
  * <p>
- * <strong>Disclaimer:</strong> experimental interface under development.
+ * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime
+ * performance overhead:
+ * <ol>
+ * <li>Extend {@link Instrument} and override only the event handling methods for which some action
+ * is needed.</li>
+ * <li>Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired
+ * <em>Truffle style</em>, documented more thoroughly elsewhere.</li>
+ * <li>Maintain as little state as possible.</li>
+ * <li>If state is necessary, make it {@code final} if possible.</li>
+ * <li>If non-final state is necessary, annotate it as {@link CompilationFinal} and call
+ * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.</li>
+ * <li>Never store a {@link Frame} value in a field.</li>
+ * <li>Minimize computation in standard execution paths.</li>
+ * <li>Callbacks to tools should be made via callbacks provided at construction and stored in
+ * {@code final} fields.</li>
+ * <li>Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from
+ * being inlined into fast execution paths.</li>
+ * <li>If computation is needed, and if performance is important, then the computation is best
+ * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that
+ * standard Truffle optimizations can be applied.</li>
+ * </ol>
+ * <p>
+ * Guidelines for attachment to a {@link Probe}:
+ * <ol>
+ * <li>An Instrument instance must only attached to a single {@link Probe}, each of which is
+ * associated uniquely with a specific syntactic unit of a guest language program, and thus
+ * (initially) to a specific {@linkplain Node Truffle AST node}.</li>
+ * <li>When the AST containing such a node is copied at runtime, the {@link Probe} will be shared by
+ * every copy, and so the Instrument will receive events corresponding to the intended syntactic
+ * unit of code, independent of which AST copy is being executed.</li>
+ * </ol>
+ *
+ * <p>
+ * <strong>Disclaimer:</strong> experimental; under development.
+ *
+ * @see Instrumentation
+ * @see Probe
+ * @see Instrument
+ * @see ASTNodeProber
  */
-public interface Instrument extends ExecutionEvents {
+public class Instrument extends InstrumentationNode {
+
+    protected Instrument() {
+    }
+
+    public void enter(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame) {
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, (Object) result);
+    }
 
-    /**
-     * @return the {@link Probe} to which this instrument is attached.
-     */
-    Probe getProbe();
+    public void leave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, (Object) result);
+    }
+
+    public void leave(Node astNode, VirtualFrame frame, Object result) {
+    }
+
+    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+    }
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Fri May 02 02:45:26 2014 +0200
@@ -24,10 +24,18 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 
 /**
- * Visualization services for guest language and Truffle information.
+ * Visualization services for the benefit of {@link Instrumentation}-based tools, possibly
+ * specialized for each guest language and possibly specialized for relevant information from the
+ * underlying Truffle implementation.
+ * <p>
+ * <strong>Disclaimer:</strong> experimental interface under development.
+ *
+ * @See Instrumentation
  */
 public interface Visualizer {
 
@@ -38,6 +46,21 @@
     ASTPrinter getASTPrinter();
 
     /**
+     * A short description of a source location in terms of source + line number.
+     */
+    String displaySourceLocation(Node node);
+
+    /**
+     * Describes the name of the method containing a node.
+     */
+    String displayMethodName(Node node);
+
+    /**
+     * The name of the method.
+     */
+    String displayCallTargetName(CallTarget callTarget);
+
+    /**
      * Converts a value in the guest language to a display string.
      */
     String displayValue(Object value);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java	Wed Apr 30 13:40:36 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * An {@link Instrument} that implements all {@link ExecutionEvents} notifications with empty
- * methods.
- */
-public class DefaultInstrument extends InstrumentationNodeImpl implements Instrument {
-
-    protected DefaultInstrument() {
-    }
-
-    public void enter(Node astNode, VirtualFrame frame) {
-    }
-
-    public void leave(Node astNode, VirtualFrame frame) {
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, boolean result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, byte result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, short result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, int result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, long result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, char result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, float result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, double result) {
-        leave(astNode, frame, (Object) result);
-    }
-
-    public void leave(Node astNode, VirtualFrame frame, Object result) {
-    }
-
-    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java	Fri May 02 02:45:26 2014 +0200
@@ -24,8 +24,12 @@
  */
 package com.oracle.truffle.api.instrument.impl;
 
+import java.io.*;
+
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
 
 public class DefaultVisualizer implements Visualizer {
 
@@ -39,6 +43,43 @@
         return astPrinter;
     }
 
+    public String displaySourceLocation(Node node) {
+        if (node == null) {
+            return "<unknown>";
+        }
+        SourceSection section = node.getSourceSection();
+        boolean estimated = false;
+        if (section == null) {
+            section = node.getEncapsulatingSourceSection();
+            estimated = true;
+        }
+
+        String sourceString;
+        if (section == null || section.getSource() == null) {
+            sourceString = "<unknown source>";
+        } else {
+            String sourceName = new File(section.getSource().getName()).getName();
+            int startLine = section.getStartLine();
+            sourceString = String.format("%s:%d%s", sourceName, startLine, estimated ? "~" : "");
+        }
+        return sourceString;
+    }
+
+    public String displayMethodName(Node node) {
+        if (node == null) {
+            return null;
+        }
+        RootNode root = node.getRootNode();
+        if (root == null) {
+            return "unknown";
+        }
+        return root.getCallTarget().toString();
+    }
+
+    public String displayCallTargetName(CallTarget callTarget) {
+        return callTarget.toString();
+    }
+
     public String displayValue(Object value) {
         return value.toString();
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java	Fri May 02 02:45:26 2014 +0200
@@ -30,10 +30,6 @@
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.source.*;
 
-/**
- * @author mlvdv
- *
- */
 public final class InstrumentationImpl implements Instrumentation {
 
     private final ExecutionContext context;
@@ -80,7 +76,7 @@
         if (probe != null) {
             return probe;
         }
-        probe = InstrumentationNodeImpl.createProbe(this, sourceSection, eventListener);
+        probe = InstrumentationNode.createProbe(this, sourceSection, eventListener);
 
         // Register new probe by unique SourceSection
         srcToProbe.put(sourceSection, probe);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Fri May 02 02:45:26 2014 +0200
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument.impl;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
+ * <p>
+ * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
+ */
+public abstract class InstrumentationNode extends Node implements ExecutionEvents {
+
+    // TODO (mlvdv) This is a pretty awkward design; it is a priority to revise it.
+
+    /**
+     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
+     * extent of guest language source code.
+     *
+     * @param eventListener an optional listener for certain instrumentation-related events.
+     * @return a new probe
+     */
+    static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
+        return new ProbeImpl(instrumentation, sourceSection, eventListener);
+    }
+
+    /**
+     * Next in chain.
+     */
+    @Child protected InstrumentationNode next;
+
+    protected InstrumentationNode() {
+    }
+
+    /**
+     * @return the instance of {@link Probe} to which this instrument is attached.
+     */
+    public Probe getProbe() {
+        final InstrumentationNode parent = (InstrumentationNode) getParent();
+        return parent == null ? null : parent.getProbe();
+    }
+
+    /**
+     * Add a probe to the end of this probe chain.
+     */
+    private void internalAddInstrument(Instrument newInstrument) {
+        if (next == null) {
+            this.next = insert(newInstrument);
+        } else {
+            next.internalAddInstrument(newInstrument);
+        }
+    }
+
+    private void internalRemoveInstrument(Instrument oldInstrument) {
+        if (next == null) {
+            throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
+        } else if (next == oldInstrument) {
+            if (oldInstrument.next == null) {
+                this.next = null;
+            } else {
+                this.next = insert(oldInstrument.next);
+                oldInstrument.next = null;
+            }
+        } else {
+            next.internalRemoveInstrument(oldInstrument);
+        }
+    }
+
+    /**
+     * Reports to the instance of {@link Probe} holding this instrument that some essential state
+     * has changed that requires deoptimization.
+     */
+    @CompilerDirectives.SlowPath
+    protected void notifyProbeChanged(Instrument instrument) {
+        final ProbeImpl probe = (ProbeImpl) getProbe();
+        probe.notifyProbeChanged(instrument);
+    }
+
+    private void internalEnter(Node astNode, VirtualFrame frame) {
+        enter(astNode, frame);
+        if (next != null) {
+            next.internalEnter(astNode, frame);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame) {
+        leave(astNode, frame);
+        if (next != null) {
+            next.internalLeave(astNode, frame);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, byte result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, short result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, int result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, long result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, char result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, float result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, double result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeave(Node astNode, VirtualFrame frame, Object result) {
+        leave(astNode, frame, result);
+        if (next != null) {
+            next.internalLeave(astNode, frame, result);
+        }
+    }
+
+    private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        leaveExceptional(astNode, frame, null);
+        if (next != null) {
+            next.internalLeaveExceptional(astNode, frame, e);
+        }
+    }
+
+    /**
+     * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the
+     * {@link Assumption} that none of the instruments have changed since last checked.
+     * <p>
+     * An instance is intended to be shared by every clone of the AST node with which it is
+     * originally attached, so it holds no parent pointer.
+     * <p>
+     * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
+     * for instrumentation about its AST location(s).
+     */
+    private static final class ProbeImpl extends InstrumentationNode implements Probe {
+
+        final InstrumentationImpl instrumentation;
+
+        final InstrumentEventListener eventListener;
+
+        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
+
+        /**
+         * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line
+         * will cause a halt.
+         */
+        @CompilerDirectives.CompilationFinal private boolean stepping;
+
+        /**
+         * Source information about the AST node to which this instrumentation is attached.
+         */
+        private final SourceSection probedSourceSection;
+
+        private final Set<PhylumTag> tags = EnumSet.noneOf(PhylumTag.class);
+
+        private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
+            this.instrumentation = instrumentation;
+            this.probedSourceSection = sourceSection;
+            this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener;
+            this.probeUnchanged = Truffle.getRuntime().createAssumption();
+            this.next = null;
+        }
+
+        @Override
+        public Probe getProbe() {
+            return this;
+        }
+
+        @Override
+        protected void notifyProbeChanged(Instrument instrument) {
+            probeUnchanged.invalidate();
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        public SourceSection getSourceLocation() {
+            return probedSourceSection;
+        }
+
+        public void tagAs(PhylumTag tag) {
+            assert tag != null;
+            if (!tags.contains(tag)) {
+                tags.add(tag);
+                instrumentation.newTagAdded(this, tag);
+            }
+        }
+
+        public boolean isTaggedAs(PhylumTag tag) {
+            assert tag != null;
+            return tags.contains(tag);
+        }
+
+        public Set<PhylumTag> getPhylumTags() {
+            return tags;
+        }
+
+        public void setStepping(boolean stepping) {
+            if (this.stepping != stepping) {
+                this.stepping = stepping;
+                probeUnchanged.invalidate();
+                probeUnchanged = Truffle.getRuntime().createAssumption();
+            }
+        }
+
+        public boolean isStepping() {
+            return stepping;
+        }
+
+        @CompilerDirectives.SlowPath
+        public void addInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalAddInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        @CompilerDirectives.SlowPath
+        public void removeInstrument(Instrument instrument) {
+            probeUnchanged.invalidate();
+            super.internalRemoveInstrument(instrument);
+            probeUnchanged = Truffle.getRuntime().createAssumption();
+        }
+
+        public void notifyEnter(Node astNode, VirtualFrame frame) {
+            if (stepping || next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                if (stepping) {
+                    eventListener.haltedAt(astNode, frame.materialize());
+                }
+                if (next != null) {
+                    next.internalEnter(astNode, frame);
+                }
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeave(astNode, frame, result);
+            }
+        }
+
+        public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+            if (next != null) {
+                if (!probeUnchanged.isValid()) {
+                    CompilerDirectives.transferToInterpreter();
+                }
+                next.internalLeaveExceptional(astNode, frame, e);
+            }
+        }
+
+        public void enter(Node astNode, VirtualFrame frame) {
+        }
+
+        public void leave(Node astNode, VirtualFrame frame) {
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, boolean result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, byte result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, short result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, int result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, long result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, char result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, float result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, double result) {
+            leave(astNode, frame, (Object) result);
+        }
+
+        public void leave(Node astNode, VirtualFrame frame, Object result) {
+        }
+
+        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java	Wed Apr 30 13:40:36 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,448 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument.impl;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments.
- * <p>
- * Coordinates propagation of Truffle AST {@link ExecutionEvents}.
- */
-public abstract class InstrumentationNodeImpl extends Node implements ExecutionEvents {
-
-    // TODO (mlvdv) This is a pretty awkward design.
-
-    /**
-     * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection}
-     * extent of guest language source code.
-     *
-     * @param eventListener an optional listener for certain instrumentation-related events.
-     * @return a new probe
-     */
-    static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
-        return new ProbeImpl(instrumentation, sourceSection, eventListener);
-    }
-
-    /**
-     * Next in chain.
-     */
-    @Child protected InstrumentationNodeImpl next;
-
-    protected InstrumentationNodeImpl() {
-    }
-
-    /**
-     * @return the instance of {@link Probe} to which this instrument is attached.
-     */
-    public Probe getProbe() {
-        final InstrumentationNodeImpl parent = (InstrumentationNodeImpl) getParent();
-        return parent == null ? null : parent.getProbe();
-    }
-
-    /**
-     * Add a probe to the end of this probe chain.
-     */
-    void internalAddInstrument(InstrumentationNodeImpl newInstrument) {
-        if (next == null) {
-            this.next = insert(newInstrument);
-        } else {
-            next.internalAddInstrument(newInstrument);
-        }
-    }
-
-    void internalRemoveInstrument(InstrumentationNodeImpl oldInstrument) {
-        if (next == null) {
-            throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument);
-        } else if (next == oldInstrument) {
-            if (oldInstrument.next == null) {
-                this.next = null;
-            } else {
-                this.next = insert(oldInstrument.next);
-                oldInstrument.next = null;
-            }
-        } else {
-            next.internalRemoveInstrument(oldInstrument);
-        }
-    }
-
-    /**
-     * Reports to the instance of {@link Probe} holding this instrument that some essential state
-     * has changed that requires deoptimization.
-     */
-    @CompilerDirectives.SlowPath
-    protected void notifyProbeChanged(InstrumentationNodeImpl instrument) {
-        final ProbeImpl probe = (ProbeImpl) getProbe();
-        probe.notifyProbeChanged(instrument);
-    }
-
-    private void internalEnter(Node astNode, VirtualFrame frame) {
-        enter(astNode, frame);
-        if (next != null) {
-            next.internalEnter(astNode, frame);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame) {
-        leave(astNode, frame);
-        if (next != null) {
-            next.internalLeave(astNode, frame);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, boolean result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, byte result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, short result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, int result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, long result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, char result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, float result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, double result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeave(Node astNode, VirtualFrame frame, Object result) {
-        leave(astNode, frame, result);
-        if (next != null) {
-            next.internalLeave(astNode, frame, result);
-        }
-    }
-
-    private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        leaveExceptional(astNode, frame, null);
-        if (next != null) {
-            next.internalLeaveExceptional(astNode, frame, e);
-        }
-    }
-
-    /**
-     * Holder of a chain of {@linkplain InstrumentationNodeImpl instruments}: manages the
-     * {@link Assumption} that none of the instruments have changed since last checked.
-     * <p>
-     * An instance is intended to be shared by every clone of the AST node with which it is
-     * originally attached, so it holds no parent pointer.
-     * <p>
-     * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful
-     * for instrumentation about its AST location(s).
-     */
-    private static final class ProbeImpl extends InstrumentationNodeImpl implements Probe {
-
-        final InstrumentationImpl instrumentation;
-
-        final InstrumentEventListener eventListener;
-
-        @CompilerDirectives.CompilationFinal private Assumption probeUnchanged;
-
-        /**
-         * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line
-         * will cause a halt.
-         */
-        @CompilerDirectives.CompilationFinal private boolean stepping;
-
-        /**
-         * Source information about the AST node to which this instrumentation is attached.
-         */
-        private final SourceSection probedSourceSection;
-
-        private final Set<PhylumTag> tags = EnumSet.noneOf(PhylumTag.class);
-
-        private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) {
-            this.instrumentation = instrumentation;
-            this.probedSourceSection = sourceSection;
-            this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener;
-            this.probeUnchanged = Truffle.getRuntime().createAssumption();
-            this.next = null;
-        }
-
-        @Override
-        public Probe getProbe() {
-            return this;
-        }
-
-        @Override
-        protected void notifyProbeChanged(InstrumentationNodeImpl instrument) {
-            probeUnchanged.invalidate();
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        public SourceSection getSourceLocation() {
-            return probedSourceSection;
-        }
-
-        public void tagAs(PhylumTag tag) {
-            assert tag != null;
-            if (!tags.contains(tag)) {
-                tags.add(tag);
-                instrumentation.newTagAdded(this, tag);
-            }
-        }
-
-        public boolean isTaggedAs(PhylumTag tag) {
-            assert tag != null;
-            return tags.contains(tag);
-        }
-
-        public Set<PhylumTag> getPhylumTags() {
-            return tags;
-        }
-
-        public void setStepping(boolean stepping) {
-            if (this.stepping != stepping) {
-                this.stepping = stepping;
-                probeUnchanged.invalidate();
-                probeUnchanged = Truffle.getRuntime().createAssumption();
-            }
-        }
-
-        public boolean isStepping() {
-            return stepping;
-        }
-
-        @CompilerDirectives.SlowPath
-        public void addInstrument(Instrument instrument) {
-            probeUnchanged.invalidate();
-            final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument;
-            super.internalAddInstrument(instrumentImpl);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        @CompilerDirectives.SlowPath
-        public void removeInstrument(Instrument instrument) {
-            probeUnchanged.invalidate();
-            final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument;
-            super.internalRemoveInstrument(instrumentImpl);
-            probeUnchanged = Truffle.getRuntime().createAssumption();
-        }
-
-        public void notifyEnter(Node astNode, VirtualFrame frame) {
-            if (stepping || next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                if (stepping) {
-                    eventListener.haltedAt(astNode, frame.materialize());
-                }
-                if (next != null) {
-                    next.internalEnter(astNode, frame);
-                }
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, byte result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, short result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, int result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, long result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, char result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, float result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, double result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeave(Node astNode, VirtualFrame frame, Object result) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeave(astNode, frame, result);
-            }
-        }
-
-        public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-            if (next != null) {
-                if (!probeUnchanged.isValid()) {
-                    CompilerDirectives.transferToInterpreter();
-                }
-                next.internalLeaveExceptional(astNode, frame, e);
-            }
-        }
-
-        public void enter(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame) {
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, boolean result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, byte result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, short result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, int result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, long result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, char result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, float result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, double result) {
-            leave(astNode, frame, (Object) result);
-        }
-
-        public void leave(Node astNode, VirtualFrame frame, Object result) {
-        }
-
-        public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
-        }
-
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Wed Apr 30 13:40:36 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Fri May 02 02:45:26 2014 +0200
@@ -317,16 +317,16 @@
     /**
      * <pre>
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * </pre>
-     * 
+     *
      * .
      */
     private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
@@ -978,9 +978,8 @@
 
         private List<CodeExecutableElement> createImplicitChildrenAccessors() {
             NodeData node = getModel().getNode();
-            // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> expectTypes = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null);
+            List<Set<TypeData>> expectTypes = new ArrayList<>(prototype);
 
             for (ExecutableTypeData executableType : node.getExecutableTypes()) {
                 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
@@ -998,8 +997,7 @@
             }
 
             List<CodeExecutableElement> methods = new ArrayList<>();
-            @SuppressWarnings("unchecked")
-            List<Set<TypeData>> visitedList = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
+            List<Set<TypeData>> visitedList = new ArrayList<>(prototype);
             for (SpecializationData spec : node.getSpecializations()) {
                 int signatureIndex = -1;
                 for (ActualParameter param : spec.getParameters()) {
--- a/mx/mx_graal.py	Wed Apr 30 13:40:36 2014 +0200
+++ b/mx/mx_graal.py	Fri May 02 02:45:26 2014 +0200
@@ -1261,13 +1261,13 @@
 
         if mx.get_env('JDT'):
             t = Task('BuildJavaWithEcj')
-            build(['--no-native', '--jdt-warning-as-error'])
+            build(['-p', '--no-native', '--jdt-warning-as-error'])
             tasks.append(t.stop())
 
             _clean('CleanAfterEcjBuild')
 
         t = Task('BuildJavaWithJavac')
-        build(['--no-native', '--force-javac'])
+        build(['-p', '--no-native', '--force-javac'])
         tasks.append(t.stop())
 
         t = Task('Checkheaders')
--- a/mxtool/mx.py	Wed Apr 30 13:40:36 2014 +0200
+++ b/mxtool/mx.py	Fri May 02 02:45:26 2014 +0200
@@ -1553,9 +1553,13 @@
 
     def _init_classpaths(self):
         myDir = dirname(__file__)
+        outDir = join(dirname(__file__), '.jdk' + str(self.version))
+        if not exists(outDir):
+            os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
-        subprocess.check_call([self.javac, '-d', myDir, javaSource])
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', myDir, 'ClasspathDump']).split('|')]
+        if not exists(join(outDir, 'ClasspathDump.class')):
+            subprocess.check_call([self.javac, '-d', outDir, javaSource])
+        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', outDir, 'ClasspathDump']).split('|')]
         if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
             warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
@@ -1790,6 +1794,131 @@
 
 # Builtin commands
 
+def _defaultEcjPath():
+    return get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
+
+class JavaCompileTask:
+    def __init__(self, args, proj, reason, javafilelist, jdk, outputDir, deps):
+        self.proj = proj
+        self.reason = reason
+        self.javafilelist = javafilelist
+        self.deps = deps
+        self.jdk = jdk
+        self.outputDir = outputDir
+        self.done = False
+        self.args = args
+
+    def __str__(self):
+        return self.proj.name
+
+    def logCompilation(self, compiler):
+        log('Compiling Java sources for {} with {}... [{}]'.format(self.proj.name, compiler, self.reason))
+
+    def execute(self):
+        argfileName = join(self.proj.dir, 'javafilelist.txt')
+        argfile = open(argfileName, 'wb')
+        argfile.write('\n'.join(self.javafilelist))
+        argfile.close()
+
+        processorArgs = []
+
+        aps = self.proj.annotation_processors()
+        if len(aps) > 0:
+            processorPath = classpath(aps, resolve=True)
+            genDir = self.proj.source_gen_dir()
+            if exists(genDir):
+                shutil.rmtree(genDir)
+            os.mkdir(genDir)
+            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        else:
+            processorArgs += ['-proc:none']
+
+        args = self.args
+        jdk = self.jdk
+        outputDir = self.outputDir
+        compliance = str(jdk.javaCompliance)
+        cp = classpath(self.proj.name, includeSelf=True)
+        toBeDeleted = [argfileName]
+
+        jdtJar = None
+        if not args.javac and args.jdt is not None:
+            if not args.jdt.endswith('.jar'):
+                abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt)
+            jdtJar = args.jdt
+            if not exists(jdtJar):
+                if os.path.abspath(jdtJar) == os.path.abspath(_defaultEcjPath()) and get_env('JDT', None) is None:
+                    # Silently ignore JDT if default location is used but does not exist
+                    jdtJar = None
+                else:
+                    abort('Eclipse batch compiler jar does not exist: ' + args.jdt)
+
+        try:
+            if not jdtJar:
+                mainJava = java()
+                if not args.error_prone:
+                    self.logCompilation('javac')
+                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    if jdk.debug_port is not None:
+                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
+                    javacCmd += processorArgs
+                    javacCmd += ['@' + argfile.name]
+
+                    if not args.warnAPI:
+                        javacCmd.append('-XDignore.symbol.file')
+                    run(javacCmd)
+                else:
+                    self.logCompilation('javac (with error-prone)')
+                    javaArgs = ['-Xmx1g']
+                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javacArgs += processorArgs
+                    javacArgs += ['@' + argfile.name]
+                    if not args.warnAPI:
+                        javacArgs.append('-XDignore.symbol.file')
+                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
+            else:
+                self.logCompilation('JDT')
+
+                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
+
+                jdtArgs = ['-' + compliance,
+                         '-cp', cp, '-g', '-enableJavadoc',
+                         '-d', outputDir,
+                         '-bootclasspath', jdk.bootclasspath(),
+                         '-endorseddirs', jdk.endorseddirs(),
+                         '-extdirs', jdk.extdirs()]
+                jdtArgs += processorArgs
+
+                jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs')
+                rootJdtProperties = join(self.proj.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
+                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
+                    # Try to fix a missing properties file by running eclipseinit
+                    eclipseinit([], buildProcessorJars=False)
+                if not exists(jdtProperties):
+                    log('JDT properties file {0} not found'.format(jdtProperties))
+                else:
+                    with open(jdtProperties) as fp:
+                        origContent = fp.read()
+                        content = origContent
+                        if args.jdt_warning_as_error:
+                            content = content.replace('=warning', '=error')
+                        if not args.jdt_show_task_tags:
+                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
+                    if origContent != content:
+                        jdtPropertiesTmp = jdtProperties + '.tmp'
+                        with open(jdtPropertiesTmp, 'w') as fp:
+                            fp.write(content)
+                        toBeDeleted.append(jdtPropertiesTmp)
+                        jdtArgs += ['-properties', jdtPropertiesTmp]
+                    else:
+                        jdtArgs += ['-properties', jdtProperties]
+                jdtArgs.append('@' + argfile.name)
+
+                run_java(jdtVmArgs + jdtArgs)
+        finally:
+            for n in toBeDeleted:
+                os.remove(n)
+            self.done = True
+
 def build(args, parser=None):
     """compile the Java and C sources, linking the latter
 
@@ -1800,11 +1929,10 @@
     if not suppliedParser:
         parser = ArgumentParser(prog='mx build')
 
-    defaultEcjPath = get_env('JDT', join(_primary_suite.mxDir, 'ecj.jar'))
-
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
+    parser.add_argument('-p', action='store_true', dest='parallelize', help='parallelizes Java compilation')
     parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one')
     parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
     parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)')
@@ -1815,7 +1943,7 @@
     parser.add_argument('--jdt-show-task-tags', action='store_true', help='show task tags as Eclipse batch compiler warnings')
     compilerSelect = parser.add_mutually_exclusive_group()
     compilerSelect.add_argument('--error-prone', dest='error_prone', help='path to error-prone.jar', metavar='<path>')
-    compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler (default: ' + defaultEcjPath + ')', default=defaultEcjPath, metavar='<path>')
+    compilerSelect.add_argument('--jdt', help='path to ecj.jar, the Eclipse batch compiler', default=_defaultEcjPath(), metavar='<path>')
     compilerSelect.add_argument('--force-javac', action='store_true', dest='javac', help='use javac despite ecj.jar is found or not')
 
 
@@ -1824,20 +1952,6 @@
 
     args = parser.parse_args(args)
 
-    jdtJar = None
-    if not args.javac and args.jdt is not None:
-        if not args.jdt.endswith('.jar'):
-            abort('Path for Eclipse batch compiler does not look like a jar file: ' + args.jdt)
-        jdtJar = args.jdt
-        if not exists(jdtJar):
-            if os.path.abspath(jdtJar) == os.path.abspath(defaultEcjPath) and get_env('JDT', None) is None:
-                # Silently ignore JDT if default location is used but does not exist
-                jdtJar = None
-            else:
-                abort('Eclipse batch compiler jar does not exist: ' + args.jdt)
-
-    built = set()
-
     if args.only is not None:
         # N.B. This build will not include dependencies including annotation processor dependencies
         sortedProjects = [project(name) for name in args.only.split(',')]
@@ -1870,6 +1984,7 @@
                 shutil.rmtree(join(genDir, f))
         return outputDir
 
+    tasks = {}
     for p in sortedProjects:
         if p.native:
             if args.native:
@@ -1879,7 +1994,6 @@
                     run([gmake_cmd(), 'clean'], cwd=p.dir)
 
                 run([gmake_cmd()], cwd=p.dir)
-                built.add(p.name)
             continue
         else:
             if not args.java:
@@ -1893,17 +2007,19 @@
         if not jdk:
             log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance))
             continue
-        compliance = str(jdk.javaCompliance)
 
         outputDir = prepareOutputDirs(p, args.clean)
 
-        cp = classpath(p.name, includeSelf=True)
         sourceDirs = p.source_dirs()
         buildReason = 'forced build' if args.force else None
+        taskDeps = []
         if not buildReason:
-            for dep in p.all_deps([], False):
-                if dep.name in built:
-                    buildReason = dep.name + ' rebuilt'
+            for dep in p.all_deps([], includeLibs=False, includeAnnotationProcessors=True):
+                taskDep = tasks.get(dep.name)
+                if taskDep:
+                    if not buildReason:
+                        buildReason = dep.name + ' rebuilt'
+                    taskDeps.append(taskDep)
 
         jasminAvailable = None
         javafilelist = []
@@ -1959,7 +2075,6 @@
                             buildReason = 'class file(s) out of date'
                             break
 
-        aps = p.annotation_processors()
         apsOutOfDate = p.update_current_annotation_processors_file()
         if apsOutOfDate:
             buildReason = 'annotation processor(s) changed'
@@ -1972,99 +2087,86 @@
             logv('[no Java sources for {0} - skipping]'.format(p.name))
             continue
 
-        # Ensure that the output directories are clean
-        # prepareOutputDirs(p, True)
-
-        built.add(p.name)
-
-        argfileName = join(p.dir, 'javafilelist.txt')
-        argfile = open(argfileName, 'wb')
-        argfile.write('\n'.join(javafilelist))
-        argfile.close()
-
-        processorArgs = []
-
-        if len(aps) > 0:
-            processorPath = classpath(aps, resolve=True)
-            genDir = p.source_gen_dir()
-            if exists(genDir):
-                shutil.rmtree(genDir)
-            os.mkdir(genDir)
-            processorArgs += ['-processorpath', join(processorPath), '-s', genDir]
+        task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, taskDeps)
+
+        if args.parallelize:
+            # Best to initialize class paths on main process
+            jdk.bootclasspath()
+            task.proc = None
+            tasks[p.name] = task
         else:
-            processorArgs += ['-proc:none']
-
-        toBeDeleted = [argfileName]
-        try:
-
-            def logCompilation(p, compiler, reason):
-                log('Compiling Java sources for {} with {}... [{}]'.format(p.name, compiler, reason))
-
-            if not jdtJar:
-                mainJava = java()
-                if not args.error_prone:
-                    logCompilation(p, 'javac', buildReason)
-                    javacCmd = [mainJava.javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    if jdk.debug_port is not None:
-                        javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
-                    javacCmd += processorArgs
-                    javacCmd += ['@' + argfile.name]
-
-                    if not args.warnAPI:
-                        javacCmd.append('-XDignore.symbol.file')
-                    run(javacCmd)
+            task.execute()
+
+    if args.parallelize:
+
+        def joinTasks(tasks):
+            failed = []
+            for t in tasks:
+                t.proc.join()
+                if t.proc.exitcode != 0:
+                    failed.append(t)
+            return failed
+
+        def checkTasks(tasks):
+            active = []
+            for t in tasks:
+                if t.proc.is_alive():
+                    active.append(t)
+                else:
+                    if t.proc.exitcode != 0:
+                        return ([], joinTasks(tasks))
+            return (active, [])
+
+        def remainingDepsDepth(task):
+            if task._d is None:
+                incompleteDeps = [d for d in task.deps if d.proc is None or d.proc.is_alive()]
+                if len(incompleteDeps) == 0:
+                    task._d = 0
                 else:
-                    logCompilation(p, 'javac (with error-prone)', buildReason)
-                    javaArgs = ['-Xmx1g']
-                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
-                    javacArgs += processorArgs
-                    javacArgs += ['@' + argfile.name]
-                    if not args.warnAPI:
-                        javacArgs.append('-XDignore.symbol.file')
-                    run_java(javaArgs + ['-cp', os.pathsep.join([mainJava.toolsjar, args.error_prone]), 'com.google.errorprone.ErrorProneCompiler'] + javacArgs)
-            else:
-                logCompilation(p, 'JDT', buildReason)
-
-                jdtVmArgs = ['-Xmx1g', '-jar', jdtJar]
-
-                jdtArgs = ['-' + compliance,
-                         '-cp', cp, '-g', '-enableJavadoc',
-                         '-d', outputDir,
-                         '-bootclasspath', jdk.bootclasspath(),
-                         '-endorseddirs', jdk.endorseddirs(),
-                         '-extdirs', jdk.extdirs()]
-                jdtArgs += processorArgs
-
-
-                jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs')
-                rootJdtProperties = join(p.suite.mxDir, 'eclipse-settings', 'org.eclipse.jdt.core.prefs')
-                if not exists(jdtProperties) or os.path.getmtime(jdtProperties) < os.path.getmtime(rootJdtProperties):
-                    # Try to fix a missing properties file by running eclipseinit
-                    eclipseinit([], buildProcessorJars=False)
-                if not exists(jdtProperties):
-                    log('JDT properties file {0} not found'.format(jdtProperties))
+                    task._d = max([remainingDepsDepth(t) for t in incompleteDeps]) + 1
+            return task._d
+
+        def sortWorklist(tasks):
+            for t in tasks:
+                t._d = None
+            return sorted(tasks, lambda x, y: remainingDepsDepth(x) - remainingDepsDepth(y))
+
+        import multiprocessing
+        cpus = multiprocessing.cpu_count()
+        worklist = sortWorklist(tasks.values())
+        active = []
+        while len(worklist) != 0:
+            while True:
+                active, failed = checkTasks(active)
+                if len(failed) != 0:
+                    assert not active, active
+                    break
+                if len(active) == cpus:
+                    # Sleep for 1 second
+                    time.sleep(1)
                 else:
-                    with open(jdtProperties) as fp:
-                        origContent = fp.read()
-                        content = origContent
-                        if args.jdt_warning_as_error:
-                            content = content.replace('=warning', '=error')
-                        if not args.jdt_show_task_tags:
-                            content = content + '\norg.eclipse.jdt.core.compiler.problem.tasks=ignore'
-                    if origContent != content:
-                        jdtPropertiesTmp = jdtProperties + '.tmp'
-                        with open(jdtPropertiesTmp, 'w') as fp:
-                            fp.write(content)
-                        toBeDeleted.append(jdtPropertiesTmp)
-                        jdtArgs += ['-properties', jdtPropertiesTmp]
-                    else:
-                        jdtArgs += ['-properties', jdtProperties]
-                jdtArgs.append('@' + argfile.name)
-
-                run_java(jdtVmArgs + jdtArgs)
-        finally:
-            for n in toBeDeleted:
-                os.remove(n)
+                    break
+
+            def executeTask(task):
+                task.execute()
+
+            def depsDone(task):
+                for d in task.deps:
+                    if d.proc is None or d.proc.exitcode is None:
+                        return False
+                return True
+
+            for task in worklist:
+                if depsDone(task):
+                    worklist.remove(task)
+                    task.proc = multiprocessing.Process(target=executeTask, args=(task,))
+                    task.proc.start()
+                    active.append(task)
+                if len(active) == cpus:
+                    break
+
+            worklist = sortWorklist(worklist)
+        joinTasks(active)
 
     for dist in _dists.values():
         archive(['@' + dist.name])
@@ -2258,7 +2360,7 @@
         return []
 
     pnames = [p.name for p in projs]
-    build(['--projects', ",".join(pnames)])
+    build(['--jdt-warning-as-error', '--projects', ",".join(pnames)])
     return archive(pnames)
 
 def pylint(args):
--- a/src/share/vm/classfile/systemDictionary.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.cpp	Fri May 02 02:45:26 2014 +0200
@@ -216,7 +216,7 @@
 // Forwards to resolve_instance_class_or_null
 
 Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
-  assert(!THREAD->is_Compiler_thread(),
+  assert(THREAD->can_call_java(),
          err_msg("can not load classes with compiler thread: class=%s, classloader=%s",
                  class_name->as_C_string(),
                  class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()));
@@ -2347,7 +2347,7 @@
                                                           TRAPS) {
   methodHandle empty;
   assert(EnableInvokeDynamic, "");
-  assert(!THREAD->is_Compiler_thread(), "");
+  assert(THREAD->can_call_java() ,"");
   Handle method_type =
     SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty));
   if (false) {  // FIXME: Decide if the Java upcall should resolve signatures.
@@ -2400,7 +2400,7 @@
   if (spe != NULL && spe->method_type() != NULL) {
     assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), "");
     return Handle(THREAD, spe->method_type());
-  } else if (THREAD->is_Compiler_thread()) {
+  } else if (!THREAD->can_call_java()) {
     warning("SystemDictionary::find_method_handle_type called from compiler thread");  // FIXME
     return Handle();  // do not attempt from within compiler, unless it was cached
   }
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri May 02 02:45:26 2014 +0200
@@ -367,7 +367,7 @@
   template(compileTheWorld_name,                  "compileTheWorld")                                                                  \
   template(shutdownCompiler_name,                 "shutdownCompiler")                                                                 \
   template(compileMethod_name,                    "compileMethod")                                                                    \
-  template(compileMethod_signature,               "(JIZ)V")                                                                           \
+  template(compileMethod_signature,               "(JIJZ)V")                                                                          \
   template(setOption_name,                        "setOption")                                                                        \
   template(setOption_signature,                   "(Ljava/lang/String;)Z")                                                            \
   template(finalizeOptions_name,                  "finalizeOptions")                                                                  \
--- a/src/share/vm/compiler/compileBroker.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp	Fri May 02 02:45:26 2014 +0200
@@ -804,7 +804,7 @@
 
 #if defined(COMPILERGRAAL)
   _compilers[1] = graal;
-  c2_count = 0;
+  c2_count = UseGraalCompilationQueue ? 0 : c2_count;
 #endif // COMPILERGRAAL
 
 #ifdef COMPILER2
@@ -1143,22 +1143,24 @@
     return;
   }
 
-#if defined(COMPILERGRAAL)
-  // In tiered mode we want to only handle highest tier compiles and
-  // in non-tiered mode the default level should be
-  // CompLevel_full_optimization which equals CompLevel_highest_tier.
-  assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
-  assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
-  if (comp_level == CompLevel_full_optimization) {
-    if (!JavaThread::current()->is_graal_compiling()) {
-      bool blockingCompilation = is_compile_blocking(method, osr_bci);
-      GraalCompiler::instance()->compile_method(method, osr_bci, blockingCompilation);
-    } else {
-      // Can't enqueue this request because there would be no one to service it, so simply return.
+#ifdef COMPILERGRAAL
+  if (UseGraalCompilationQueue) {
+    // In tiered mode we want to only handle highest tier compiles and
+    // in non-tiered mode the default level should be
+    // CompLevel_full_optimization which equals CompLevel_highest_tier.
+    assert(TieredCompilation || comp_level == CompLevel_full_optimization, "incorrect compile level");
+    assert(CompLevel_full_optimization == CompLevel_highest_tier, "incorrect level definition");
+    if (comp_level == CompLevel_full_optimization) {
+      if (!JavaThread::current()->is_graal_compiling()) {
+        bool blockingCompilation = is_compile_blocking(method, osr_bci);
+        GraalCompiler::instance()->compile_method(method, osr_bci, NULL, blockingCompilation);
+      } else {
+        // Can't enqueue this request because there would be no one to service it, so simply return.
+      }
+      return;
     }
-    return;
+    assert(TieredCompilation, "should only reach here in tiered mode");
   }
-  assert(TieredCompilation, "should only reach here in tiered mode");
 #endif // COMPILERGRAAL
 
   // Outputs from the following MutexLocker block:
@@ -1881,6 +1883,35 @@
   tty->print(s.as_string());
 }
 
+void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
+
+  if (success) {
+    task->mark_success();
+    if (ci_env != NULL) {
+      task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes());
+    }
+    if (_compilation_log != NULL) {
+      nmethod* code = task->code();
+      if (code != NULL) {
+        _compilation_log->log_nmethod(thread, code);
+      }
+    }
+  }
+
+  // simulate crash during compilation
+  assert(task->compile_id() != CICrashAt, "just as planned");
+  if (event.should_commit()) {
+    event.set_method(task->method());
+    event.set_compileID(task->compile_id());
+    event.set_compileLevel(task->comp_level());
+    event.set_succeded(task->is_success());
+    event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
+    event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
+    event.set_inlinedBytes(task->num_inlined_bytecodes());
+    event.commit();
+  }
+}
+
 // ------------------------------------------------------------------
 // CompileBroker::invoke_compiler_on_method
 //
@@ -1929,6 +1960,21 @@
   push_jni_handle_block();
   Method* target_handle = task->method();
   int compilable = ciEnv::MethodCompilable;
+  AbstractCompiler *comp = compiler(task_level);
+
+#ifdef COMPILERGRAAL
+  if (comp != NULL && comp->is_graal()) {
+    assert(!UseGraalCompilationQueue, "should not reach here");
+    GraalCompiler* graal = (GraalCompiler*) comp;
+
+    TraceTime t1("compilation", &time);
+    EventCompilation event;
+
+    graal->compile_method(target_handle, osr_bci, task, false);
+
+    post_compile(thread, task, event, task->code() != NULL, NULL);
+  } else
+#endif // COMPILERGRAAL
   {
     int system_dictionary_modification_counter;
     {
@@ -1960,7 +2006,6 @@
     TraceTime t1("compilation", &time);
     EventCompilation event;
 
-    AbstractCompiler *comp = compiler(task_level);
     if (comp == NULL) {
       ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
     } else {
@@ -1988,28 +2033,9 @@
             err_msg_res("COMPILE SKIPPED: %s",      ci_env.failure_reason());
         task->print_compilation(tty, msg);
       }
-    } else {
-      task->mark_success();
-      task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes());
-      if (_compilation_log != NULL) {
-        nmethod* code = task->code();
-        if (code != NULL) {
-          _compilation_log->log_nmethod(thread, code);
-        }
-      }
     }
-    // simulate crash during compilation
-    assert(task->compile_id() != CICrashAt, "just as planned");
-    if (event.should_commit()) {
-      event.set_method(target->get_Method());
-      event.set_compileID(compile_id);
-      event.set_compileLevel(task->comp_level());
-      event.set_succeded(task->is_success());
-      event.set_isOsr(is_osr);
-      event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
-      event.set_inlinedBytes(task->num_inlined_bytecodes());
-      event.commit();
-    }
+
+    post_compile(thread, task, event, !ci_env.failing(), &ci_env);
   }
   pop_jni_handle_block();
 
--- a/src/share/vm/compiler/compileBroker.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.hpp	Fri May 02 02:45:26 2014 +0200
@@ -28,6 +28,7 @@
 #include "ci/compilerInterface.hpp"
 #include "compiler/abstractCompiler.hpp"
 #include "runtime/perfData.hpp"
+#include "trace/tracing.hpp"
 
 class nmethod;
 class nmethodLocker;
@@ -339,6 +340,7 @@
   static void wait_for_completion(CompileTask* task);
 
   static void invoke_compiler_on_method(CompileTask* task);
+  static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
   static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level);
   static void push_jni_handle_block();
   static void pop_jni_handle_block();
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri May 02 02:45:26 2014 +0200
@@ -422,12 +422,13 @@
     methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code));
     jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code);
     jint id = HotSpotCompiledNmethod::id(compiled_code);
+    CompileTask* task = (CompileTask*) (address) HotSpotCompiledNmethod::ctask(compiled_code);
     if (id == -1) {
       // Make sure a valid compile_id is associated with every compile
       id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci);
     }
     result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-        GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, id, false, installed_code, speculation_log);
+        GraalCompiler::instance(), _debug_recorder, _dependencies, task, id, false, installed_code, speculation_log);
     cb = nm;
   }
 
--- a/src/share/vm/graal/graalCompiler.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri May 02 02:45:26 2014 +0200
@@ -44,7 +44,10 @@
 
 // Initialization
 void GraalCompiler::initialize() {
-  
+  if (!should_perform_init()) {
+    return;
+  }
+
   ThreadToNativeFromVM trans(JavaThread::current());
   JavaThread* THREAD = JavaThread::current();
   TRACE_graal_1("GraalCompiler::initialize");
@@ -100,7 +103,7 @@
     if (UseCompiler) {
       _external_deopt_i2c_entry = create_external_deopt_i2c();
 #ifdef COMPILERGRAAL
-      bool bootstrap = FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal;
+      bool bootstrap = UseGraalCompilationQueue && (FLAG_IS_DEFAULT(BootstrapGraal) ? !TieredCompilation : BootstrapGraal);
 #else
       bool bootstrap = false;
 #endif
@@ -172,7 +175,7 @@
   return buffer_blob;
 }
 
-void GraalCompiler::compile_method(methodHandle method, int entry_bci, jboolean blocking) {
+void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task, jboolean blocking) {
   GRAAL_EXCEPTION_CONTEXT
   if (!_initialized) {
     CompilationPolicy::policy()->delay_compilation(method());
@@ -182,7 +185,7 @@
   assert(_initialized, "must already be initialized");
   ResourceMark rm;
   thread->set_is_graal_compiling(true);
-  VMToCompiler::compileMethod(method(), entry_bci, blocking);
+  VMToCompiler::compileMethod(method(), entry_bci, (jlong) (address) task, blocking);
   thread->set_is_graal_compiling(false);
 }
 
--- a/src/share/vm/graal/graalCompiler.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.hpp	Fri May 02 02:45:26 2014 +0200
@@ -60,7 +60,7 @@
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
-  void compile_method(methodHandle target, int entry_bci, jboolean blocking);
+  void compile_method(methodHandle target, int entry_bci, CompileTask* task, jboolean blocking);
 
   // Print compilation timers and statistics
   virtual void print_timers();
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri May 02 02:45:26 2014 +0200
@@ -156,8 +156,6 @@
 
   //------------------------------------------------------------------------------------------------
 
-  set_address("handleDeoptStub", SharedRuntime::deopt_blob()->unpack());
-
   set_address("registerFinalizerAddress", SharedRuntime::register_finalizer);
   set_address("exceptionHandlerForReturnAddressAddress", SharedRuntime::exception_handler_for_return_address);
   set_address("osrMigrationEndAddress", SharedRuntime::OSR_migration_end);
--- a/src/share/vm/graal/graalGlobals.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp	Fri May 02 02:45:26 2014 +0200
@@ -52,6 +52,9 @@
   COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true,                 \
           "Bootstrap Graal before running Java main method"))               \
                                                                             \
+  COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, false,      \
+          "Use non-native compilation queue for Graal"))                    \
+                                                                            \
   product(bool, ForceGraalInitialization, false,                            \
           "Force VM to initialize the compiler even if not used")           \
                                                                             \
--- a/src/share/vm/graal/graalJavaAccess.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri May 02 02:45:26 2014 +0200
@@ -88,6 +88,7 @@
     oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                     \
     int_field(HotSpotCompiledNmethod, entryBCI)                                                                                                                \
     int_field(HotSpotCompiledNmethod, id)                                                                                                                      \
+    long_field(HotSpotCompiledNmethod, ctask)                                                                                                                  \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 02 02:45:26 2014 +0200
@@ -111,7 +111,7 @@
   check_pending_exception("Error while calling finalizeOptions");
 }
 
-void VMToCompiler::compileMethod(Method* method, int entry_bci, jboolean blocking) {
+void VMToCompiler::compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking) {
   assert(method != NULL, "just checking");
   Thread* THREAD = Thread::current();
   JavaValue result(T_VOID);
@@ -119,6 +119,7 @@
   args.push_oop(instance());
   args.push_long((jlong) (address) method);
   args.push_int(entry_bci);
+  args.push_long(ctask);
   args.push_int(blocking);
   JavaCalls::call_interface(&result, vmToCompilerKlass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD);
   check_pending_exception("Error while calling compileMethod");
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 02 02:45:26 2014 +0200
@@ -60,8 +60,8 @@
   // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
   static void finalizeOptions(jboolean ciTime);
 
-  // public abstract boolean compileMethod(long vmId, int entry_bci, boolean blocking);
-  static void compileMethod(Method* method, int entry_bci, jboolean blocking);
+  // public abstract boolean compileMethod(long metaspaceMethod, int entryBCI, long ctask, boolean blocking);
+  static void compileMethod(Method* method, int entry_bci, jlong ctask, jboolean blocking);
 
   // public abstract void shutdownCompiler();
   static void shutdownCompiler();
--- a/src/share/vm/interpreter/linkResolver.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/interpreter/linkResolver.cpp	Fri May 02 02:45:26 2014 +0200
@@ -113,7 +113,7 @@
     // Note: with several active threads, the must_be_compiled may be true
     //       while can_be_compiled is false; remove assert
     // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
-    if (THREAD->is_Compiler_thread()) {
+    if (!THREAD->can_call_java()) {
       // don't force compilation, resolve was on behalf of compiler
       return;
     }
@@ -364,7 +364,7 @@
         return;
       }
     } else if (iid == vmIntrinsics::_invokeGeneric
-               && !THREAD->is_Compiler_thread()
+               && THREAD->can_call_java()
                && appendix_result_or_null != NULL) {
       // This is a method with type-checking semantics.
       // We will ask Java code to spin an adapter method for it.
--- a/src/share/vm/oops/method.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/oops/method.cpp	Fri May 02 02:45:26 2014 +0200
@@ -1314,7 +1314,7 @@
 
 // These two methods are static since a GC may move the Method
 bool Method::load_signature_classes(methodHandle m, TRAPS) {
-  if (THREAD->is_Compiler_thread()) {
+  if (!THREAD->can_call_java()) {
     // There is nothing useful this routine can do from within the Compile thread.
     // Hopefully, the signature contains only well-known classes.
     // We could scan for this and return true/false, but the caller won't care.
--- a/src/share/vm/prims/jni.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/prims/jni.cpp	Fri May 02 02:45:26 2014 +0200
@@ -5174,15 +5174,19 @@
     *(JNIEnv**)penv = thread->jni_environment();
 
 #ifdef GRAAL
-    // GraalCompiler needs to have been created in compileBroker.cpp
-    GraalCompiler* graal_compiler = GraalCompiler::instance();
-    if (ForceGraalInitialization && graal_compiler == NULL) {
-      graal_compiler = new GraalCompiler();
-    }
-    if (graal_compiler != NULL) {
-      graal_compiler->initialize();
+    if (COMPILERGRAAL_PRESENT(UseGraalCompilationQueue) NOT_COMPILERGRAAL(true)) {
+      // GraalCompiler needs to have been created in compileBroker.cpp
+      GraalCompiler* graal_compiler = GraalCompiler::instance();
+      if (ForceGraalInitialization && graal_compiler == NULL) {
+        graal_compiler = new GraalCompiler();
+      }
+      if (graal_compiler != NULL) {
+        graal_compiler->initialize();
+      } else {
+        assert(!UseCompiler, "why isn't there any compiler?");
+      }
     } else {
-      assert(!UseCompiler, "why isn't there any compiler?");
+      // Graal is initialized on a CompilerThread
     }
 #endif
 
--- a/src/share/vm/runtime/deoptimization.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Fri May 02 02:45:26 2014 +0200
@@ -359,7 +359,8 @@
 #ifdef ASSERT
   assert(cb->is_deoptimization_stub() ||
          cb->is_uncommon_trap_stub() ||
-         strcmp("Stub<DeoptimizationStub.uncommonTrapHandler>", cb->name()) == 0,
+         strcmp("Stub<DeoptimizationStub.deoptimizationHandler>", cb->name()) == 0 ||
+         strcmp("Stub<UncommonTrapStub.uncommonTrapHandler>", cb->name()) == 0,
          err_msg("unexpected code blob: %s", cb->name()));
 #endif
 #else
--- a/src/share/vm/runtime/javaCalls.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/runtime/javaCalls.cpp	Fri May 02 02:45:26 2014 +0200
@@ -52,7 +52,7 @@
 
   guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code");
   assert(!thread->owns_locks(), "must release all locks when leaving VM");
-  guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
+  guarantee(thread->can_call_java(), "cannot make java calls from the compiler");
   _result   = result;
 
   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
@@ -366,7 +366,7 @@
 #endif
 
 
-  assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");
+  assert(thread->can_call_java(), "cannot compile from the compiler");
   if (CompilationPolicy::must_be_compiled(method)) {
     CompileBroker::compile_method(method, InvocationEntryBci,
                                   CompilationPolicy::policy()->initial_compile_level(),
--- a/src/share/vm/runtime/thread.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/runtime/thread.cpp	Fri May 02 02:45:26 2014 +0200
@@ -2253,7 +2253,7 @@
 
   // Do not throw asynchronous exceptions against the compiler thread
   // (the compiler thread should not be a Java thread -- fix in 1.4.2)
-  if (is_Compiler_thread()) return;
+  if (!can_call_java()) return;
 
   {
     // Actually throw the Throwable against the target Thread - however
@@ -3311,6 +3311,12 @@
 #endif
 }
 
+#ifdef COMPILERGRAAL
+bool CompilerThread::can_call_java() const {
+  return _compiler != NULL && _compiler->is_graal();
+}
+#endif
+
 void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf) {
   JavaThread::oops_do(f, cld_f, cf);
   if (_scanned_nmethod != NULL && cf != NULL) {
@@ -4334,7 +4340,7 @@
   {
     MutexLockerEx ml(doLock ? Threads_lock : NULL);
     ALL_JAVA_THREADS(p) {
-      if (p->is_Compiler_thread()) continue;
+      if (!p->can_call_java()) continue;
 
       address pending = (address)p->current_pending_monitor();
       if (pending == monitor) {             // found a match
--- a/src/share/vm/runtime/thread.hpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/runtime/thread.hpp	Fri May 02 02:45:26 2014 +0200
@@ -321,6 +321,9 @@
   virtual bool is_Named_thread() const               { return false; }
   virtual bool is_Worker_thread() const              { return false; }
 
+  // Can this thread make Java upcalls
+  virtual bool can_call_java() const                 { return true;  }
+
   // Casts
   virtual WorkerThread* as_Worker_thread() const     { return NULL; }
 
@@ -1876,8 +1879,13 @@
   CompilerThread(CompileQueue* queue, CompilerCounters* counters);
 
   bool is_Compiler_thread() const                { return true; }
+
+#ifdef COMPILERGRAAL
+  virtual bool can_call_java() const;
+#endif
+
   // Hide this compiler thread from external view.
-  bool is_hidden_from_external_view() const      { return true; }
+  bool is_hidden_from_external_view() const      { return !can_call_java(); }
 
   void set_compiler(AbstractCompiler* c)         { _compiler = c; }
   AbstractCompiler* compiler() const             { return _compiler; }
--- a/src/share/vm/runtime/vmStructs.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp	Fri May 02 02:45:26 2014 +0200
@@ -1307,6 +1307,7 @@
   nonstatic_field(CompileTask,                 _osr_bci,                                     int)                                    \
   nonstatic_field(CompileTask,                 _comp_level,                                  int)                                    \
   nonstatic_field(CompileTask,                 _compile_id,                                  uint)                                   \
+  nonstatic_field(CompileTask,                 _num_inlined_bytecodes,                       int)                                    \
   nonstatic_field(CompileTask,                 _next,                                        CompileTask*)                           \
   nonstatic_field(CompileTask,                 _prev,                                        CompileTask*)                           \
                                                                                                                                      \
--- a/src/share/vm/utilities/exceptions.cpp	Wed Apr 30 13:40:36 2014 +0200
+++ b/src/share/vm/utilities/exceptions.cpp	Fri May 02 02:45:26 2014 +0200
@@ -84,7 +84,7 @@
 #endif // ASSERT
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);
@@ -107,7 +107,7 @@
   }
 
   if (thread->is_VM_thread()
-      || thread->is_Compiler_thread() ) {
+      || !thread->can_call_java() ) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
     thread->set_pending_exception(Universe::vm_exception(), file, line);