changeset 21399:307a1ee8f714

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Fri, 15 May 2015 11:55:52 +0200
parents 427f3b505656 (current diff) f27373c035fb (diff)
children 33d3be2548d6 8adf2a826696
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java
diffstat 103 files changed, 4243 insertions(+), 4579 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java	Fri May 15 11:55:52 2015 +0200
@@ -64,6 +64,13 @@
     }
 
     /**
+     * Returns the name of this code blob.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
      * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0
      * otherwise.
      */
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java	Fri May 15 11:55:52 2015 +0200
@@ -68,6 +68,10 @@
             return result;
         }
 
+        public boolean isAssumptionFree() {
+            return assumptions.length == 0;
+        }
+
         public void add(AssumptionResult<T> other) {
             Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length);
             System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length);
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java	Fri May 15 11:55:52 2015 +0200
@@ -256,16 +256,18 @@
      */
     static PrimitiveConstant forIntegerKind(Kind kind, long i) {
         switch (kind) {
+            case Boolean:
+                return forBoolean(i != 0);
             case Byte:
-                return new PrimitiveConstant(kind, (byte) i);
+                return forByte((byte) i);
             case Short:
-                return new PrimitiveConstant(kind, (short) i);
+                return forShort((short) i);
             case Char:
-                return new PrimitiveConstant(kind, (char) i);
+                return forChar((char) i);
             case Int:
-                return new PrimitiveConstant(kind, (int) i);
+                return forInt((int) i);
             case Long:
-                return new PrimitiveConstant(kind, i);
+                return forLong(i);
             default:
                 throw new IllegalArgumentException("not an integer kind: " + kind);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+public class LineNumberTableImpl implements LineNumberTable {
+
+    private final int[] lineNumbers;
+    private final int[] bci;
+
+    public LineNumberTableImpl(int[] lineNumbers, int[] bci) {
+        this.lineNumbers = lineNumbers;
+        this.bci = bci;
+    }
+
+    @Override
+    public int[] getLineNumberEntries() {
+        return lineNumbers;
+    }
+
+    @Override
+    public int[] getBciEntries() {
+        return bci;
+    }
+
+    @Override
+    public int getLineNumber(@SuppressWarnings("hiding") int bci) {
+        for (int i = 0; i < this.bci.length - 1; i++) {
+            if (this.bci[i] <= bci && bci < this.bci[i + 1]) {
+                return lineNumbers[i];
+            }
+        }
+        return lineNumbers[lineNumbers.length - 1];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+public class LocalImpl implements Local {
+
+    private final String name;
+    private final int startBci;
+    private final int endBci;
+    private final int slot;
+    private final JavaType type;
+
+    public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) {
+        this.name = name;
+        this.startBci = startBci;
+        this.endBci = endBci;
+        this.slot = slot;
+        this.type = type;
+    }
+
+    @Override
+    public int getStartBCI() {
+        return startBci;
+    }
+
+    @Override
+    public int getEndBCI() {
+        return endBci;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public JavaType getType() {
+        return type;
+    }
+
+    @Override
+    public int getSlot() {
+        return slot;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof LocalImpl)) {
+            return false;
+        }
+        LocalImpl that = (LocalImpl) obj;
+        return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type);
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "LocalImpl<name=" + name + ", type=" + type + ", startBci=" + startBci + ", endBci=" + endBci + ", slot=" + slot + ">";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.meta;
+
+import java.util.*;
+
+public class LocalVariableTableImpl implements LocalVariableTable {
+
+    private final Local[] locals;
+
+    public LocalVariableTableImpl(Local[] locals) {
+        this.locals = locals;
+    }
+
+    @Override
+    public Local getLocal(int slot, int bci) {
+        Local result = null;
+        for (Local local : locals) {
+            if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) {
+                if (result == null) {
+                    result = local;
+                } else {
+                    throw new IllegalStateException("Locals overlap!");
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Local[] getLocals() {
+        return locals;
+    }
+
+    @Override
+    public Local[] getLocalsAt(int bci) {
+        List<Local> result = new ArrayList<>();
+        for (Local l : locals) {
+            if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) {
+                result.add(l);
+            }
+        }
+        return result.toArray(new Local[result.size()]);
+    }
+
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java	Fri May 15 11:55:52 2015 +0200
@@ -54,26 +54,18 @@
      */
     public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length");
 
-    protected final boolean immutable;
-
     public static LocationIdentity any() {
         return ANY_LOCATION;
     }
 
-    protected LocationIdentity(boolean immutable) {
-        this.immutable = immutable;
-    }
-
     /**
      * Denotes a location is unchanging in all cases. Not that this is different than the Java
      * notion of final which only requires definite assignment.
      */
-    public final boolean isImmutable() {
-        return immutable;
-    }
+    public abstract boolean isImmutable();
 
     public final boolean isMutable() {
-        return !immutable;
+        return !isImmutable();
     }
 
     public final boolean isAny() {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Fri May 15 11:55:52 2015 +0200
@@ -46,11 +46,12 @@
         }
     }
 
-    protected final String name;
+    private final String name;
+    private final boolean immutable;
 
     private NamedLocationIdentity(String name, boolean immutable) {
-        super(immutable);
         this.name = name;
+        this.immutable = immutable;
     }
 
     /**
@@ -87,6 +88,11 @@
     }
 
     @Override
+    public boolean isImmutable() {
+        return immutable;
+    }
+
+    @Override
     public String toString() {
         return name + (isImmutable() ? ":final" : "");
     }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri May 15 11:55:52 2015 +0200
@@ -52,6 +52,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
@@ -64,6 +65,7 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove;
+import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
@@ -130,6 +132,28 @@
         }
     }
 
+    /**
+     * Checks whether the supplied constant can be used without loading it into a register for store
+     * operations, i.e., on the right hand side of a memory access.
+     *
+     * @param c The constant to check.
+     * @return True if the constant can be used directly, false if the constant needs to be in a
+     *         register.
+     */
+    protected final boolean canStoreConstant(JavaConstant c) {
+        // there is no immediate move of 64-bit constants on Intel
+        switch (c.getKind()) {
+            case Long:
+                return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
+            case Double:
+                return false;
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof AMD64AddressValue) {
             return new LeaOp(dst, (AMD64AddressValue) src);
@@ -263,6 +287,183 @@
         return result;
     }
 
+    private static LIRKind toStackKind(LIRKind kind) {
+        if (kind.getPlatformKind() instanceof Kind) {
+            Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind();
+            return kind.changeType(stackKind);
+        } else {
+            return kind;
+        }
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AMD64AddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(toStackKind(kind));
+        switch ((Kind) kind.getPlatformKind()) {
+            case Boolean:
+                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state));
+                break;
+            case Byte:
+                append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
+                break;
+            case Char:
+                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state));
+                break;
+            case Short:
+                append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
+                break;
+            case Int:
+                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
+                break;
+            case Float:
+                append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
+                break;
+            case Double:
+                append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        return result;
+    }
+
+    protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
+        if (value.isNull()) {
+            assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
+            OperandSize size = kind == Kind.Int ? DWORD : QWORD;
+            append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
+        } else {
+            AMD64MIOp op = AMD64MIOp.MOV;
+            OperandSize size;
+            long imm;
+
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                    op = AMD64MIOp.MOVB;
+                    size = BYTE;
+                    imm = value.asInt();
+                    break;
+                case Char:
+                case Short:
+                    size = WORD;
+                    imm = value.asInt();
+                    break;
+                case Int:
+                    size = DWORD;
+                    imm = value.asInt();
+                    break;
+                case Long:
+                    size = QWORD;
+                    imm = value.asLong();
+                    break;
+                case Float:
+                    size = DWORD;
+                    imm = Float.floatToRawIntBits(value.asFloat());
+                    break;
+                case Double:
+                    size = QWORD;
+                    imm = Double.doubleToRawLongBits(value.asDouble());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind);
+            }
+
+            if (NumUtil.isInt(imm)) {
+                append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
+            } else {
+                emitStore(kind, address, asAllocatable(value), state);
+            }
+        }
+    }
+
+    protected void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
+                break;
+            case Char:
+            case Short:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
+                break;
+            case Int:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
+                break;
+            case Float:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
+                break;
+            case Double:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) {
+        AMD64AddressValue storeAddress = asAddressValue(address);
+        Kind kind = (Kind) lirKind.getPlatformKind();
+        if (isConstant(input)) {
+            emitStoreConst(kind, storeAddress, asConstant(input), state);
+        } else {
+            emitStore(kind, storeAddress, asAllocatable(input), state);
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        LIRKind kind = newValue.getLIRKind();
+        assert kind.equals(expectedValue.getLIRKind());
+        Kind memKind = (Kind) kind.getPlatformKind();
+
+        AMD64AddressValue addressValue = asAddressValue(address);
+        RegisterValue raxRes = AMD64.rax.asValue(kind);
+        emitMove(raxRes, expectedValue);
+        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
+
+        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndAdd(Value address, Value delta) {
+        LIRKind kind = delta.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
+        return result;
+    }
+
+    @Override
+    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
+        LIRKind kind = newValue.getLIRKind();
+        Kind memKind = (Kind) kind.getPlatformKind();
+        Variable result = newVariable(kind);
+        AMD64AddressValue addressValue = asAddressValue(address);
+        append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
+        return result;
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!";
+        append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
     @Override
     public void emitJump(LabelRef label) {
         assert label != null;
@@ -1066,16 +1267,36 @@
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
-            Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
-            int mask = (int) CodeUtil.mask(fromBits);
-            append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
+
+            LIRKind resultKind = LIRKind.derive(inputVal);
+            OperandSize resultSize;
             if (toBits > 32) {
-                Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
-                emitMove(longResult, result);
-                return longResult;
+                resultKind = resultKind.changeType(Kind.Long);
+                resultSize = QWORD;
             } else {
-                return result;
+                resultKind = resultKind.changeType(Kind.Int);
+                resultSize = DWORD;
+            }
+
+            switch (fromBits) {
+                case 8:
+                    return emitConvertOp(resultKind, MOVZXB, resultSize, inputVal);
+                case 16:
+                    return emitConvertOp(resultKind, MOVZX, resultSize, inputVal);
+                case 32:
+                    return emitConvertOp(resultKind, MOV, DWORD, inputVal);
             }
+
+            // odd bit count, fall back on manual masking
+            Variable result = newVariable(resultKind);
+            JavaConstant mask;
+            if (toBits > 32) {
+                mask = JavaConstant.forLong(CodeUtil.mask(fromBits));
+            } else {
+                mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits));
+            }
+            append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask));
+            return result;
         }
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri May 15 11:55:52 2015 +0200
@@ -45,4 +45,6 @@
     public Fields getData() {
         return data;
     }
+
+    public abstract Fields[] getAllFields();
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri May 15 11:55:52 2015 +0200
@@ -48,6 +48,8 @@
      */
     private final Class<?>[] types;
 
+    private final Class<?>[] declaringClasses;
+
     public static Fields forClass(Class<?> clazz, Class<?> endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) {
         FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset);
         scanner.scan(clazz, endClazz, includeTransient);
@@ -59,11 +61,13 @@
         this.offsets = new long[fields.size()];
         this.names = new String[offsets.length];
         this.types = new Class[offsets.length];
+        this.declaringClasses = new Class[offsets.length];
         int index = 0;
         for (FieldsScanner.FieldInfo f : fields) {
             offsets[index] = f.offset;
             names[index] = f.name;
             types[index] = f.type;
+            declaringClasses[index] = f.declaringClass;
             index++;
         }
     }
@@ -77,7 +81,7 @@
 
     public static void translateInto(Fields fields, ArrayList<FieldsScanner.FieldInfo> infos) {
         for (int index = 0; index < fields.getCount(); index++) {
-            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index]));
+            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index]));
         }
     }
 
@@ -217,6 +221,10 @@
         return other.offsets[index] == offsets[index];
     }
 
+    public long[] getOffsets() {
+        return offsets;
+    }
+
     /**
      * Gets the name of a field.
      *
@@ -235,6 +243,10 @@
         return types[index];
     }
 
+    public Class<?> getDeclaringClass(int index) {
+        return declaringClasses[index];
+    }
+
     /**
      * Checks that a given field is assignable from a given value.
      *
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java	Fri May 15 11:55:52 2015 +0200
@@ -60,11 +60,13 @@
         public final long offset;
         public final String name;
         public final Class<?> type;
+        public final Class<?> declaringClass;
 
-        public FieldInfo(long offset, String name, Class<?> type) {
+        public FieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
             this.offset = offset;
             this.name = name;
             this.type = type;
+            this.declaringClass = declaringClass;
         }
 
         /**
@@ -117,6 +119,6 @@
     }
 
     protected void scanField(Field field, long offset) {
-        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType()));
+        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass()));
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri May 15 11:55:52 2015 +0200
@@ -286,7 +286,7 @@
     public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionValue<Boolean> OptLivenessAnalysis = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptClearNonLiveLocals = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri May 15 11:55:52 2015 +0200
@@ -113,7 +113,6 @@
         }
         objectStates.clear();
 
-        assert frame.validateFormat(false);
         return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri May 15 11:55:52 2015 +0200
@@ -57,7 +57,7 @@
 
     public static void translateInto(Edges edges, ArrayList<EdgeInfo> infos) {
         for (int index = 0; index < edges.getCount(); index++) {
-            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index)));
+            infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index)));
         }
     }
 
@@ -547,10 +547,6 @@
         }
     }
 
-    public long[] getOffsets() {
-        return this.offsets;
-    }
-
     public void pushAll(Node node, NodeStack stack) {
         int index = 0;
         int curDirectCount = this.directCount;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Fri May 15 11:55:52 2015 +0200
@@ -47,7 +47,7 @@
 
     public static void translateInto(InputEdges inputs, ArrayList<InputInfo> infos) {
         for (int index = 0; index < inputs.getCount(); index++) {
-            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.inputTypes[index], inputs.isOptional(index)));
+            infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index)));
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri May 15 11:55:52 2015 +0200
@@ -241,6 +241,11 @@
         return shortName;
     }
 
+    @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, inputs, successors};
+    }
+
     public int[] iterableIds() {
         nodeIterableCount.increment();
         return iterableIds;
@@ -288,8 +293,8 @@
      */
     protected static class EdgeInfo extends FieldsScanner.FieldInfo {
 
-        public EdgeInfo(long offset, String name, Class<?> type) {
-            super(offset, name, type);
+        public EdgeInfo(long offset, String name, Class<?> type, Class<?> declaringClass) {
+            super(offset, name, type, declaringClass);
         }
 
         /**
@@ -317,8 +322,8 @@
         final InputType inputType;
         final boolean optional;
 
-        public InputInfo(long offset, String name, Class<?> type, InputType inputType, boolean optional) {
-            super(offset, name, type);
+        public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) {
+            super(offset, name, type, declaringClass);
             this.inputType = inputType;
             this.optional = optional;
         }
@@ -375,7 +380,7 @@
                     } else {
                         inputType = optionalInputAnnotation.value();
                     }
-                    inputs.add(new InputInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
+                    inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
                 } else if (successorAnnotation != null) {
                     if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
                         // NodeSuccessorList fields should not be final since they are
@@ -387,7 +392,7 @@
                         GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field);
                         directSuccessors++;
                     }
-                    successors.add(new EdgeInfo(offset, field.getName(), type));
+                    successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass()));
                 } else {
                     GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
                     GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -41,7 +41,9 @@
     }
 
     public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode[] args) {
-        b.addPush(new ForeignCallNode(foreignCalls, descriptor, args));
+        ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args);
+        foreignCall.setBci(b.bci());
+        b.addPush(foreignCall);
         return true;
     }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Fri May 15 11:55:52 2015 +0200
@@ -131,9 +131,10 @@
 
     private final boolean eagerResolving;
     private final boolean omitAllExceptionEdges;
+    private final boolean omitAssertions;
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final DebugInfoMode debugInfoMode;
-    private final boolean doLivenessAnalysis;
+    private final boolean clearNonLiveLocals;
     private boolean useProfiling;
     private final Plugins plugins;
 
@@ -161,13 +162,14 @@
         Full,
     }
 
-    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis,
-                    Plugins plugins) {
+    protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes,
+                    boolean clearNonLiveLocals, Plugins plugins) {
         this.eagerResolving = eagerResolving;
         this.omitAllExceptionEdges = omitAllExceptionEdges;
+        this.omitAssertions = omitAssertions;
         this.debugInfoMode = debugInfoMode;
         this.skippedExceptionTypes = skippedExceptionTypes;
-        this.doLivenessAnalysis = doLivenessAnalysis;
+        this.clearNonLiveLocals = clearNonLiveLocals;
         this.useProfiling = true;
         this.plugins = plugins;
     }
@@ -179,7 +181,7 @@
      */
     public GraphBuilderConfiguration copy() {
         Plugins newPlugins = new Plugins(plugins);
-        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins);
+        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins);
         result.useProfiling = useProfiling;
         return result;
     }
@@ -193,20 +195,24 @@
     }
 
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
     public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) {
-        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
+    }
+
+    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
     public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) {
         ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins);
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins);
     }
 
-    public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) {
-        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, plugins);
+    public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) {
+        return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins);
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -221,6 +227,10 @@
         return omitAllExceptionEdges;
     }
 
+    public boolean omitAssertions() {
+        return omitAssertions;
+    }
+
     public boolean insertNonSafepointDebugInfo() {
         return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal();
     }
@@ -233,32 +243,32 @@
         return debugInfoMode == DebugInfoMode.Simple;
     }
 
-    public boolean doLivenessAnalysis() {
-        return doLivenessAnalysis;
+    public boolean clearNonLiveLocals() {
+        return clearNonLiveLocals;
     }
 
     public static GraphBuilderConfiguration getDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins);
+        return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
     }
 
     /**
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Fri May 15 11:55:52 2015 +0200
@@ -36,7 +36,8 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object.
+ * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
+ * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
  */
 public interface GraphBuilderContext {
 
@@ -178,7 +179,7 @@
      * Gets the first ancestor parsing context that is not parsing a
      * {@linkplain #parsingIntrinsic() intrinsic}.
      */
-    default GraphBuilderContext getNonReplacementAncestor() {
+    default GraphBuilderContext getNonIntrinsicAncestor() {
         GraphBuilderContext ancestor = getParent();
         while (ancestor != null && ancestor.parsingIntrinsic()) {
             ancestor = ancestor.getParent();
@@ -187,7 +188,7 @@
     }
 
     /**
-     * Gets the method currently being parsed.
+     * Gets the method being parsed by this context.
      */
     ResolvedJavaMethod getMethod();
 
@@ -206,9 +207,18 @@
      */
     JavaType getInvokeReturnType();
 
+    default Stamp getInvokeReturnStamp() {
+        JavaType returnType = getInvokeReturnType();
+        if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) {
+            return StampFactory.declared((ResolvedJavaType) returnType);
+        } else {
+            return StampFactory.forKind(returnType.getKind());
+        }
+    }
+
     /**
-     * Gets the inline depth of this context. 0 implies this is the context for the compilation root
-     * method.
+     * Gets the inline depth of this context. A return value of 0 implies that this is the context
+     * for the parse root.
      */
     default int getDepth() {
         GraphBuilderContext parent = getParent();
@@ -216,7 +226,8 @@
     }
 
     /**
-     * Determines if the current parsing context is a snippet or method substitution.
+     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
+     * by an intrinsic.
      */
     default boolean parsingIntrinsic() {
         return getIntrinsic() != null;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Fri May 15 11:55:52 2015 +0200
@@ -227,6 +227,14 @@
     }
 
     /**
+     * Disallows new registrations of new plugins, and creates the internal tables for method
+     * lookup.
+     */
+    public void closeRegistration() {
+        plugins.createEntries();
+    }
+
+    /**
      * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
      * before searching in this object.
      */
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -40,7 +40,7 @@
         JavaConstant result = constantReflection.readConstantFieldValue(field, receiver);
         if (result != null) {
             ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess);
-            b.addPush(constantNode.getKind().getStackKind(), constantNode);
+            b.addPush(field.getKind(), constantNode);
             return true;
         }
         return false;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java	Fri May 15 11:55:52 2015 +0200
@@ -62,7 +62,7 @@
                     idVerifierMap.put(holder, id);
                 }
             } else {
-                assert idVerifierMap.get(holder) == id;
+                assert !idVerifierMap.containsKey(holder) || idVerifierMap.get(holder) == id;
             }
             return id;
         }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java	Fri May 15 11:55:52 2015 +0200
@@ -199,38 +199,7 @@
 
     public V get(MethodIdHolder method) {
         if (entries == null) {
-            // 'assignIds' synchronizes on a global lock which ensures thread safe
-            // allocation of identifiers across all MethodIdHolder objects
-            MethodIdHolder.assignIds(new Consumer<MethodIdAllocator>() {
-
-                public void accept(MethodIdAllocator idAllocator) {
-                    if (entries == null) {
-                        if (registrations.isEmpty()) {
-                            entries = allocateEntries(0);
-                        } else {
-                            int max = Integer.MIN_VALUE;
-                            for (MethodKey<V> methodKey : registrations) {
-                                MethodIdHolder m = methodKey.resolve(metaAccess);
-                                int id = idAllocator.assignId(m);
-                                if (id < minId) {
-                                    minId = id;
-                                }
-                                if (id > max) {
-                                    max = id;
-                                }
-                                methodKey.id = id;
-                            }
-
-                            int length = (max - minId) + 1;
-                            entries = allocateEntries(length);
-                            for (MethodKey<V> m : registrations) {
-                                int index = m.id - minId;
-                                entries[index] = m.value;
-                            }
-                        }
-                    }
-                }
-            });
+            createEntries();
         }
 
         int id = method.getMethodId();
@@ -238,6 +207,41 @@
         return index >= 0 && index < entries.length ? entries[index] : null;
     }
 
+    public void createEntries() {
+        // 'assignIds' synchronizes on a global lock which ensures thread safe
+        // allocation of identifiers across all MethodIdHolder objects
+        MethodIdHolder.assignIds(new Consumer<MethodIdAllocator>() {
+
+            public void accept(MethodIdAllocator idAllocator) {
+                if (entries == null) {
+                    if (registrations.isEmpty()) {
+                        entries = allocateEntries(0);
+                    } else {
+                        int max = Integer.MIN_VALUE;
+                        for (MethodKey<V> methodKey : registrations) {
+                            MethodIdHolder m = methodKey.resolve(metaAccess);
+                            int id = idAllocator.assignId(m);
+                            if (id < minId) {
+                                minId = id;
+                            }
+                            if (id > max) {
+                                max = id;
+                            }
+                            methodKey.id = id;
+                        }
+
+                        int length = (max - minId) + 1;
+                        entries = allocateEntries(length);
+                        for (MethodKey<V> m : registrations) {
+                            int index = m.id - minId;
+                            entries[index] = m.value;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
     @Override
     public String toString() {
         return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", "));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 15 11:55:52 2015 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.amd64;
 
 import static com.oracle.graal.amd64.AMD64.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*;
 import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
@@ -34,13 +33,10 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
 import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
@@ -52,8 +48,6 @@
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
-import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.asm.*;
@@ -494,15 +488,6 @@
         }
     }
 
-    private static LIRKind toStackKind(LIRKind kind) {
-        if (kind.getPlatformKind() instanceof Kind) {
-            Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind();
-            return kind.changeType(stackKind);
-        } else {
-            return kind;
-        }
-    }
-
     public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
         Variable frameSizeVariable = load(frameSize);
         Variable framePcVariable = load(framePc);
@@ -512,47 +497,8 @@
     }
 
     @Override
-    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
-        AMD64AddressValue loadAddress = asAddressValue(address);
-        Variable result = newVariable(toStackKind(kind));
-        switch ((Kind) kind.getPlatformKind()) {
-            case Boolean:
-                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state));
-                break;
-            case Byte:
-                append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
-                break;
-            case Char:
-                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state));
-                break;
-            case Short:
-                append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
-                break;
-            case Int:
-                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
-                break;
-            case Long:
-            case Object:
-                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
-                break;
-            case Float:
-                append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
-                break;
-            case Double:
-                append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-        return result;
-    }
-
-    private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
-        if (value.isNull()) {
-            assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
-            OperandSize size = kind == Kind.Int ? DWORD : QWORD;
-            append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
-        } else if (value instanceof HotSpotConstant) {
+    protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
+        if (value instanceof HotSpotConstant && value.isNonNull()) {
             HotSpotConstant c = (HotSpotConstant) value;
             if (c.isCompressed()) {
                 assert kind == Kind.Int;
@@ -565,86 +511,7 @@
                 emitStore(kind, address, asAllocatable(value), state);
             }
         } else {
-            AMD64MIOp op = AMD64MIOp.MOV;
-            OperandSize size;
-            long imm;
-
-            switch (kind) {
-                case Boolean:
-                case Byte:
-                    op = AMD64MIOp.MOVB;
-                    size = BYTE;
-                    imm = value.asInt();
-                    break;
-                case Char:
-                case Short:
-                    size = WORD;
-                    imm = value.asInt();
-                    break;
-                case Int:
-                    size = DWORD;
-                    imm = value.asInt();
-                    break;
-                case Long:
-                    size = QWORD;
-                    imm = value.asLong();
-                    break;
-                case Float:
-                    size = DWORD;
-                    imm = Float.floatToRawIntBits(value.asFloat());
-                    break;
-                case Double:
-                    size = QWORD;
-                    imm = Double.doubleToRawLongBits(value.asDouble());
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind);
-            }
-
-            if (NumUtil.isInt(imm)) {
-                append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
-            } else {
-                emitStore(kind, address, asAllocatable(value), state);
-            }
-        }
-    }
-
-    private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
-        switch (kind) {
-            case Boolean:
-            case Byte:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
-                break;
-            case Char:
-            case Short:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
-                break;
-            case Int:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
-                break;
-            case Long:
-            case Object:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
-                break;
-            case Float:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
-                break;
-            case Double:
-                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) {
-        AMD64AddressValue storeAddress = asAddressValue(address);
-        Kind kind = (Kind) lirKind.getPlatformKind();
-        if (isConstant(input)) {
-            emitStoreConst(kind, storeAddress, asConstant(input), state);
-        } else {
-            emitStore(kind, storeAddress, asAllocatable(input), state);
+            super.emitStoreConst(kind, address, value, state);
         }
     }
 
@@ -699,40 +566,7 @@
         }
     }
 
-    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
-        LIRKind kind = newValue.getLIRKind();
-        assert kind.equals(expectedValue.getLIRKind());
-        Kind memKind = (Kind) kind.getPlatformKind();
-
-        AMD64AddressValue addressValue = asAddressValue(address);
-        RegisterValue raxRes = AMD64.rax.asValue(kind);
-        emitMove(raxRes, expectedValue);
-        append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
-
-        assert trueValue.getLIRKind().equals(falseValue.getLIRKind());
-        Variable result = newVariable(trueValue.getLIRKind());
-        append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
-        return result;
-    }
-
-    public Value emitAtomicReadAndAdd(Value address, Value delta) {
-        LIRKind kind = delta.getLIRKind();
-        Kind memKind = (Kind) kind.getPlatformKind();
-        Variable result = newVariable(kind);
-        AMD64AddressValue addressValue = asAddressValue(address);
-        append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta)));
-        return result;
-    }
-
-    public Value emitAtomicReadAndWrite(Value address, Value newValue) {
-        LIRKind kind = newValue.getLIRKind();
-        Kind memKind = (Kind) kind.getPlatformKind();
-        Variable result = newVariable(kind);
-        AMD64AddressValue addressValue = asAddressValue(address);
-        append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue)));
-        return result;
-    }
-
+    @Override
     public void emitNullCheck(Value address, LIRFrameState state) {
         if (address.getLIRKind().getPlatformKind() == Kind.Int) {
             CompressEncoding encoding = config.getOopEncoding();
@@ -744,8 +578,7 @@
             }
             append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
         } else {
-            assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!";
-            append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
+            super.emitNullCheck(address, state);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -63,10 +62,6 @@
                     return null;
                 }
             }
-        } else if (substituteClass == CRC32Substitutions.class) {
-            if (!config.useCRC32Intrinsics) {
-                return null;
-            }
         }
         return super.registerMethodSubstitution(cr, originalMethod, substituteMethod);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import com.oracle.graal.api.meta.*;
-
-public class LineNumberTableImpl implements LineNumberTable {
-
-    private final int[] lineNumbers;
-    private final int[] bci;
-
-    public LineNumberTableImpl(int[] lineNumbers, int[] bci) {
-        this.lineNumbers = lineNumbers;
-        this.bci = bci;
-    }
-
-    @Override
-    public int[] getLineNumberEntries() {
-        return lineNumbers;
-    }
-
-    @Override
-    public int[] getBciEntries() {
-        return bci;
-    }
-
-    @Override
-    public int getLineNumber(@SuppressWarnings("hiding") int bci) {
-        for (int i = 0; i < this.bci.length - 1; i++) {
-            if (this.bci[i] <= bci && bci < this.bci[i + 1]) {
-                return lineNumbers[i];
-            }
-        }
-        return lineNumbers[lineNumbers.length - 1];
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import com.oracle.graal.api.meta.*;
-
-public class LocalImpl implements Local {
-
-    private final String name;
-    private final int startBci;
-    private final int endBci;
-    private final int slot;
-    private final JavaType type;
-
-    public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) {
-        this.name = name;
-        this.startBci = startBci;
-        this.endBci = endBci;
-        this.slot = slot;
-        this.type = type;
-    }
-
-    @Override
-    public int getStartBCI() {
-        return startBci;
-    }
-
-    @Override
-    public int getEndBCI() {
-        return endBci;
-    }
-
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public JavaType getType() {
-        return type;
-    }
-
-    @Override
-    public int getSlot() {
-        return slot;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof LocalImpl)) {
-            return false;
-        }
-        LocalImpl that = (LocalImpl) obj;
-        return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type);
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "LocalImpl<name=" + name + ", type=" + type + ", startBci=" + startBci + ", endBci=" + endBci + ", slot=" + slot + ">";
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.debug;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-
-public class LocalVariableTableImpl implements LocalVariableTable {
-
-    private final Local[] locals;
-
-    public LocalVariableTableImpl(Local[] locals) {
-        this.locals = locals;
-    }
-
-    @Override
-    public Local getLocal(int slot, int bci) {
-        Local result = null;
-        for (Local local : locals) {
-            if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) {
-                if (result == null) {
-                    result = local;
-                } else {
-                    throw new IllegalStateException("Locals overlap!");
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Local[] getLocals() {
-        return locals;
-    }
-
-    @Override
-    public Local[] getLocalsAt(int bci) {
-        List<Local> result = new ArrayList<>();
-        for (Local l : locals) {
-            if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) {
-                result.add(l);
-            }
-        }
-        return result.toArray(new Local[result.size()]);
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Fri May 15 11:55:52 2015 +0200
@@ -197,8 +197,7 @@
         assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || HotSpotLoadFieldPlugin.FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver;
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
 
-        if (receiver == null) {
-            assert hotspotField.isStatic();
+        if (hotspotField.isStatic()) {
             if (hotspotField.isFinal() || hotspotField.isStable()) {
                 ResolvedJavaType holder = hotspotField.getDeclaringClass();
                 if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable(hotspotField)) {
@@ -213,7 +212,6 @@
              * for non-static final fields, we must assume that they are only initialized if they
              * have a non-default value.
              */
-            assert !hotspotField.isStatic();
             Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object();
 
             // Canonicalization may attempt to process an unsafe read before
@@ -259,18 +257,17 @@
 
     private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) {
         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
-        if (receiver == null) {
-            assert hotspotField.isStatic();
+        if (hotspotField.isStatic()) {
             HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
             if (holder.isInitialized()) {
                 return memoryAccess.readUnsafeConstant(hotspotField.getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset());
             }
-            return null;
         } else {
-            assert !hotspotField.isStatic();
-            assert receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object());
-            return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset());
+            if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) {
+                return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset());
+            }
         }
+        return null;
     }
 
     public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri May 15 11:55:52 2015 +0200
@@ -26,6 +26,7 @@
 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
 
 import java.lang.invoke.*;
+import java.util.zip.*;
 
 import sun.reflect.*;
 
@@ -65,7 +66,7 @@
      */
     public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
                     SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) {
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess());
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
@@ -76,7 +77,8 @@
         plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
         plugins.setTypeCheckPlugin(wordOperationPlugin);
         plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements));
-        plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin));
+        plugins.setGenericInvocationPlugin(new MethodHandleInvocationPlugin(constantReflection.getMethodHandleAccess(), new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification,
+                        wordOperationPlugin)));
 
         registerObjectPlugins(invocationPlugins);
         registerClassPlugins(plugins);
@@ -86,6 +88,7 @@
         registerReflectionPlugins(invocationPlugins);
         registerStableOptionPlugins(invocationPlugins);
         registerAESPlugins(invocationPlugins, config);
+        registerCRC32Plugins(invocationPlugins, config);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, !config.useHeapProfiler);
 
         return plugins;
@@ -248,4 +251,17 @@
             }
         }
     }
+
+    private static void registerCRC32Plugins(InvocationPlugins plugins, HotSpotVMConfig config) {
+        if (config.useCRC32Intrinsics) {
+            assert config.aescryptEncryptBlockStub != 0L;
+            assert config.aescryptDecryptBlockStub != 0L;
+            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
+            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
+            Registration r = new Registration(plugins, CRC32.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
+            r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Fri May 15 11:55:52 2015 +0200
@@ -22,23 +22,14 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*;
-
-import java.lang.invoke.*;
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.phases.*;
-import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 import com.oracle.graal.replacements.nodes.*;
@@ -48,12 +39,10 @@
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
-    final MethodHandleAccessProvider methodHandleAccess;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) {
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
         super(metaAccess);
         this.config = config;
-        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -74,68 +63,6 @@
         super.register(plugin, declaringClass, name, argumentTypes);
     }
 
-    private ResolvedJavaType methodHandleClass;
-    private final Map<IntrinsicMethod, InvocationPlugin> methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class);
-
-    @Override
-    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
-        if (methodHandleClass == null) {
-            methodHandleClass = plugins.getMetaAccess().lookupJavaType(MethodHandle.class);
-        }
-        if (method.getDeclaringClass().equals(methodHandleClass)) {
-            HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
-            int intrinsicId = hsMethod.intrinsicId();
-            if (intrinsicId != 0) {
-                /*
-                 * The methods of MethodHandle that need substitution are signature-polymorphic,
-                 * i.e., the VM replicates them for every signature that they are actually used for.
-                 */
-                IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId);
-                if (intrinsicMethod != null) {
-                    InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod);
-                    if (plugin == null) {
-                        plugin = new InvocationPlugin() {
-                            public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) {
-                                InvokeKind invokeKind = b.getInvokeKind();
-                                if (invokeKind != InvokeKind.Static) {
-                                    receiver.get();
-                                }
-                                JavaType invokeReturnType = b.getInvokeReturnType();
-                                InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod,
-                                                b.bci(), invokeReturnType, argsIncludingReceiver);
-                                if (invoke == null) {
-                                    MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), invokeReturnType, argsIncludingReceiver);
-                                    if (invokeReturnType.getKind() == Kind.Void) {
-                                        b.add(methodHandleNode);
-                                    } else {
-                                        b.addPush(methodHandleNode);
-                                    }
-                                } else {
-                                    CallTargetNode callTarget = invoke.callTarget();
-                                    NodeInputList<ValueNode> argumentsList = callTarget.arguments();
-                                    ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]);
-                                    for (ValueNode arg : args) {
-                                        b.recursiveAppend(arg);
-                                    }
-                                    b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args);
-                                }
-                                return true;
-                            }
-
-                            public boolean isSignaturePolymorphic() {
-                                return true;
-                            }
-                        };
-                        methodHandlePlugins.put(intrinsicMethod, plugin);
-                    }
-                    return plugin;
-                }
-            }
-
-        }
-        return super.lookupInvocation(method);
-    }
-
     @Override
     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
         for (Node node : newNodes) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 
@@ -65,18 +64,6 @@
 
     public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) {
         if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
-            // Javac does not allow use of "$assertionsDisabled" for a field name but
-            // Eclipse does in which case a suffix is added to the generated field.
-            if (b.parsingIntrinsic() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) {
-                // For methods called indirectly from intrinsics, we (silently) disable
-                // assertions so that the parser won't see calls to the AssertionError
-                // constructor (all Invokes must be removed from intrinsics - see
-                // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of
-                // assertions in intrinsics is forbidden.
-                assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)");
-                b.addPush(ConstantNode.forBoolean(true));
-                return true;
-            }
             return tryReadField(b, staticField, null);
         }
         return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -54,11 +54,15 @@
         HotSpotResolvedJavaField inner;
 
         public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) {
-            super(false);
             this.inner = inner;
         }
 
         @Override
+        public boolean isImmutable() {
+            return false;
+        }
+
+        @Override
         public boolean equals(Object obj) {
             if (this == obj) {
                 return true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -36,7 +36,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.nodes.*;
 
 /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import static sun.misc.Version.*;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-
-/**
- * A call target that replaces itself in the graph when being lowered by restoring the original
- * {@link MethodHandle} invocation target. Prior to
- * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
- * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
- * that case, the original invocation must be restored with all of its original arguments. Why?
- * HotSpot linkage for {@link MethodHandle} intrinsics (see
- * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
- * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
- * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
- * invocation drops these arguments which means the interpreter won't find them.
- */
-@NodeInfo
-public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
-
-    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
-
-    /**
-     * Creates a call target for an invocation on a direct target derived by resolving a constant
-     * {@link MethodHandle}.
-     */
-    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
-                    ValueNode[] originalArguments, JavaType originalReturnType) {
-        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
-            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
-            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType);
-        }
-        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
-    }
-
-    protected final ResolvedJavaMethod originalTargetMethod;
-    protected final JavaType originalReturnType;
-    @Input NodeInputList<ValueNode> originalArguments;
-
-    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
-                    ValueNode[] originalArguments, JavaType originalReturnType) {
-        super(TYPE, invokeKind, targetMethod, arguments, returnType);
-        this.originalTargetMethod = originalTargetMethod;
-        this.originalReturnType = originalReturnType;
-        this.originalArguments = new NodeInputList<>(this, originalArguments);
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        MethodCallTargetNode replacement = graph().add(
-                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
-
-        // Replace myself...
-        this.replaceAndDelete(replacement);
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java	Fri May 15 11:55:52 2015 +0200
@@ -31,7 +31,6 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.word.*;
@@ -39,25 +38,8 @@
 /**
  * Substitutions for {@link CRC32}.
  */
-@ClassSubstitution(value = CRC32.class, defaultGuard = CRC32Substitutions.Guard.class)
 public class CRC32Substitutions {
 
-    public static class Guard implements SubstitutionGuard {
-
-        @SuppressWarnings("unused") private HotSpotVMConfig config;
-
-        public Guard(HotSpotVMConfig config) {
-            this.config = config;
-        }
-
-        public boolean execute() {
-            /*
-             * Disabled until MethodSubstitutions are compiled like snipppets.
-             */
-            return false; // return config.useCRC32Intrinsics;
-        }
-    }
-
     /**
      * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}.
      */
@@ -66,7 +48,6 @@
         return runtime().getConfig().crcTableAddress;
     }
 
-    @MethodSubstitution(isStatic = true)
     static int update(int crc, int b) {
         int c = ~crc;
         int index = (b ^ c) & 0xFF;
@@ -76,13 +57,11 @@
         return ~result;
     }
 
-    @MethodSubstitution(isStatic = true)
     static int updateBytes(int crc, byte[] buf, int off, int len) {
         Word bufAddr = Word.unsigned(GetObjectAddressNode.get(buf) + arrayBaseOffset(Kind.Byte) + off);
         return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
-    @MethodSubstitution(isStatic = true, optional = true)
     static int updateByteBuffer(int crc, long addr, int off, int len) {
         Word bufAddr = Word.unsigned(addr).add(off);
         return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri May 15 11:55:52 2015 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import java.util.zip.*;
-
 import sun.misc.*;
 import sun.reflect.*;
 
@@ -43,7 +41,6 @@
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
-        replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
-import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Node for invocation methods defined on the class {@link MethodHandle}.
- */
-@NodeInfo
-public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
-    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
-
-    protected final IntrinsicMethod intrinsicMethod;
-
-    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
-        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
-        this.intrinsicMethod = intrinsicMethod;
-    }
-
-    /**
-     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
-     * invocation on another method with possibly transformed arguments.
-     *
-     * @param assumptions object for recording any speculations made during the transformation
-     * @param methodHandleAccess objects for accessing the implementation internals of a
-     *            {@link MethodHandle}
-     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
-     * @param bci the BCI of the original {@link MethodHandle} call
-     * @param returnType return type of the original {@link MethodHandle} call
-     * @param arguments arguments to the original {@link MethodHandle} call
-     * @return a more direct invocation derived from the {@link MethodHandle} call or null
-     */
-    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode... arguments) {
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
-        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
-        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
-        if (invoke != null) {
-            assert invoke.graph() == null;
-            invoke = graph().addOrUniqueWithInputs(invoke);
-            invoke.setStateAfter(stateAfter());
-            FixedNode currentNext = next();
-            replaceAtUsages(invoke);
-            GraphUtil.removeFixedWithUnusedInputs(this);
-            graph().addBeforeFixed(currentNext, invoke);
-        }
-    }
-
-    /**
-     * Get the receiver of a MethodHandle.invokeBasic call.
-     *
-     * @return the receiver argument node
-     */
-    private static ValueNode getReceiver(ValueNode[] arguments) {
-        return arguments[0];
-    }
-
-    /**
-     * Get the MemberName argument of a MethodHandle.linkTo* call.
-     *
-     * @return the MemberName argument node (which is the last argument)
-     */
-    private static ValueNode getMemberName(ValueNode[] arguments) {
-        return arguments[arguments.length - 1];
-    }
-
-    /**
-     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
-     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
-     *
-     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
-     */
-    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode[] arguments) {
-        ValueNode methodHandleNode = getReceiver(arguments);
-        if (methodHandleNode.isConstant()) {
-            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
-        }
-        return null;
-    }
-
-    /**
-     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
-     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
-     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
-     * the member name argument is constant.
-     *
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
-                    JavaType returnType, ValueNode[] arguments) {
-        ValueNode memberNameNode = getMemberName(arguments);
-        if (memberNameNode.isConstant()) {
-            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
-        }
-        return null;
-    }
-
-    /**
-     * Helper function to get the {@link InvokeNode} for the targetMethod of a
-     * java.lang.invoke.MemberName.
-     *
-     * @param target the target, already loaded from the member name node
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
-                    ResolvedJavaMethod original) {
-        if (target == null) {
-            return null;
-        }
-
-        // In lambda forms we erase signature types to avoid resolving issues
-        // involving class loaders. When we optimize a method handle invoke
-        // to a direct call we must cast the receiver and arguments to its
-        // actual types.
-        Signature signature = target.getSignature();
-        final boolean isStatic = target.isStatic();
-        final int receiverSkip = isStatic ? 0 : 1;
-
-        // Cast receiver to its type.
-        if (!isStatic) {
-            JavaType receiverType = target.getDeclaringClass();
-            maybeCastArgument(arguments, 0, receiverType);
-        }
-
-        // Cast reference arguments to its type.
-        for (int index = 0; index < signature.getParameterCount(false); index++) {
-            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
-            maybeCastArgument(arguments, receiverSkip + index, parameterType);
-        }
-
-        if (target.canBeStaticallyBound()) {
-            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
-        }
-
-        // Try to get the most accurate receiver type
-        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
-            ValueNode receiver = getReceiver(arguments);
-            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
-            if (receiverType != null) {
-                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
-                if (concreteMethod != null) {
-                    assumptions.record(concreteMethod);
-                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
-                }
-            }
-        } else {
-            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
-            if (concreteMethod != null) {
-                assumptions.record(concreteMethod);
-                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Inserts a node to cast the argument at index to the given type if the given type is more
-     * concrete than the argument type.
-     *
-     * @param index of the argument to be cast
-     * @param type the type the argument should be cast to
-     */
-    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType targetType = (ResolvedJavaType) type;
-            if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments[index];
-                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
-                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
-                    arguments[index] = piNode;
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
-     *
-     * @return invoke node for the member name target
-     */
-    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
-        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        JavaType targetReturnType = target.getSignature().getReturnType(null);
-
-        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
-        // needs to be popped.
-        ValueNode[] targetArguments;
-        switch (intrinsicMethod) {
-            case INVOKE_BASIC:
-                targetArguments = arguments;
-                break;
-            case LINK_TO_STATIC:
-            case LINK_TO_SPECIAL:
-            case LINK_TO_VIRTUAL:
-            case LINK_TO_INTERFACE:
-                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-
-        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
-
-        // The call target can have a different return type than the invoker,
-        // e.g. the target returns an Object but the invoker void. In this case
-        // we need to use the stamp of the invoker. Note: always using the
-        // invoker's stamp would be wrong because it's a less concrete type
-        // (usually java.lang.Object).
-        if (returnType.getKind() == Kind.Void) {
-            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
-        } else {
-            return new InvokeNode(callTarget, bci);
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1260 +0,0 @@
-/*
- * Copyright (c) 2014, 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.java;
-
-import static com.oracle.graal.api.code.TypeCheckHints.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.bytecode.Bytecodes.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.bytecode.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.*;
-
-public abstract class AbstractBytecodeParser {
-
-    public static class Options {
-        // @formatter:off
-        @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
-        public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
-
-        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
-        public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
-
-        @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
-        public static final StableOptionValue<Boolean> InlineIntrinsicsDuringParsing = new StableOptionValue<>(true);
-
-        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
-
-        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
-
-        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
-
-        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
-        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
-
-        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
-        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
-
-        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
-
-        @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> HideSubstitutionStates = new OptionValue<>(false);
-
-        // @formatter:on
-    }
-
-    /**
-     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
-     * bytecode instructions as they are parsed.
-     */
-    public static final int TRACELEVEL_INSTRUCTIONS = 1;
-
-    /**
-     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
-     * frame state before each bytecode instruction as it is parsed.
-     */
-    public static final int TRACELEVEL_STATE = 2;
-
-    protected HIRFrameStateBuilder frameState;
-    protected BciBlock currentBlock;
-
-    protected final BytecodeStream stream;
-    protected final GraphBuilderConfiguration graphBuilderConfig;
-    protected final ResolvedJavaMethod method;
-    protected final ProfilingInfo profilingInfo;
-    protected final OptimisticOptimizations optimisticOpts;
-    protected final ConstantPool constantPool;
-    protected final MetaAccessProvider metaAccess;
-
-    protected final IntrinsicContext intrinsicContext;
-
-    /**
-     * Meters the number of actual bytecodes parsed.
-     */
-    public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
-
-    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
-                    IntrinsicContext intrinsicContext) {
-        this.graphBuilderConfig = graphBuilderConfig;
-        this.optimisticOpts = optimisticOpts;
-        this.metaAccess = metaAccess;
-        this.stream = new BytecodeStream(method.getCode());
-        this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
-        this.constantPool = method.getConstantPool();
-        this.method = method;
-        this.intrinsicContext = intrinsicContext;
-        assert metaAccess != null;
-    }
-
-    public void setCurrentFrameState(HIRFrameStateBuilder frameState) {
-        this.frameState = frameState;
-    }
-
-    protected final BytecodeStream getStream() {
-        return stream;
-    }
-
-    public int bci() {
-        return stream.currentBCI();
-    }
-
-    public void loadLocal(int index, Kind kind) {
-        frameState.push(kind, frameState.loadLocal(index));
-    }
-
-    public void storeLocal(Kind kind, int index) {
-        ValueNode value;
-        if (kind == Kind.Object) {
-            value = frameState.xpop();
-            // astore and astore_<n> may be used to store a returnAddress (jsr)
-            assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
-        } else {
-            value = frameState.pop(kind);
-        }
-        frameState.storeLocal(index, value, kind);
-    }
-
-    /**
-     * @param type the unresolved type of the constant
-     */
-    protected abstract void handleUnresolvedLoadConstant(JavaType type);
-
-    /**
-     * @param type the unresolved type of the type check
-     * @param object the object value whose type is being checked against {@code type}
-     */
-    protected abstract void handleUnresolvedCheckCast(JavaType type, ValueNode object);
-
-    /**
-     * @param type the unresolved type of the type check
-     * @param object the object value whose type is being checked against {@code type}
-     */
-    protected abstract void handleUnresolvedInstanceOf(JavaType type, ValueNode object);
-
-    /**
-     * @param type the type being instantiated
-     */
-    protected abstract void handleUnresolvedNewInstance(JavaType type);
-
-    /**
-     * @param type the type of the array being instantiated
-     * @param length the length of the array
-     */
-    protected abstract void handleUnresolvedNewObjectArray(JavaType type, ValueNode length);
-
-    /**
-     * @param type the type being instantiated
-     * @param dims the dimensions for the multi-array
-     */
-    protected abstract void handleUnresolvedNewMultiArray(JavaType type, List<ValueNode> dims);
-
-    /**
-     * @param field the unresolved field
-     * @param receiver the object containing the field or {@code null} if {@code field} is static
-     */
-    protected abstract void handleUnresolvedLoadField(JavaField field, ValueNode receiver);
-
-    /**
-     * @param field the unresolved field
-     * @param value the value being stored to the field
-     * @param receiver the object containing the field or {@code null} if {@code field} is static
-     */
-    protected abstract void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver);
-
-    /**
-     * @param type
-     */
-    protected abstract void handleUnresolvedExceptionType(JavaType type);
-
-    // protected abstract void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind);
-
-    // protected abstract DispatchBeginNode handleException(ValueNode exceptionObject, int bci);
-
-    private void genLoadConstant(int cpi, int opcode) {
-        Object con = lookupConstant(cpi, opcode);
-
-        if (con instanceof JavaType) {
-            // this is a load of class constant which might be unresolved
-            JavaType type = (JavaType) con;
-            if (type instanceof ResolvedJavaType) {
-                frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass()));
-            } else {
-                handleUnresolvedLoadConstant(type);
-            }
-        } else if (con instanceof JavaConstant) {
-            JavaConstant constant = (JavaConstant) con;
-            frameState.push(constant.getKind().getStackKind(), appendConstant(constant));
-        } else {
-            throw new Error("lookupConstant returned an object of incorrect type");
-        }
-    }
-
-    protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind);
-
-    private void genLoadIndexed(Kind kind) {
-        ValueNode index = frameState.ipop();
-        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
-        if (!tryLoadIndexedPlugin(kind, index, array)) {
-            frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
-        }
-    }
-
-    protected abstract void traceWithContext(String format, Object... args);
-
-    protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) {
-        LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin();
-        if (loadIndexedPlugin != null && loadIndexedPlugin.apply((GraphBuilderContext) this, array, index, kind)) {
-            if (TraceParserPlugins.getValue()) {
-                traceWithContext("used load indexed plugin");
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
-
-    private void genStoreIndexed(Kind kind) {
-        ValueNode value = frameState.pop(kind.getStackKind());
-        ValueNode index = frameState.ipop();
-        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
-        genStoreIndexed(array, index, kind, value);
-    }
-
-    private void stackOp(int opcode) {
-        switch (opcode) {
-            case DUP_X1: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP_X2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2_X1: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case DUP2_X2: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                ValueNode w3 = frameState.xpop();
-                ValueNode w4 = frameState.xpop();
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                frameState.xpush(w4);
-                frameState.xpush(w3);
-                frameState.xpush(w2);
-                frameState.xpush(w1);
-                break;
-            }
-            case SWAP: {
-                ValueNode w1 = frameState.xpop();
-                ValueNode w2 = frameState.xpop();
-                frameState.xpush(w1);
-                frameState.xpush(w2);
-                break;
-            }
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    protected abstract ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    protected abstract ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
-
-    private void genArithmeticOp(Kind result, int opcode) {
-        ValueNode y = frameState.pop(result);
-        ValueNode x = frameState.pop(result);
-        boolean isStrictFP = method.isStrict();
-        ValueNode v;
-        switch (opcode) {
-            case IADD:
-            case LADD:
-                v = genIntegerAdd(result, x, y);
-                break;
-            case FADD:
-            case DADD:
-                v = genFloatAdd(result, x, y, isStrictFP);
-                break;
-            case ISUB:
-            case LSUB:
-                v = genIntegerSub(result, x, y);
-                break;
-            case FSUB:
-            case DSUB:
-                v = genFloatSub(result, x, y, isStrictFP);
-                break;
-            case IMUL:
-            case LMUL:
-                v = genIntegerMul(result, x, y);
-                break;
-            case FMUL:
-            case DMUL:
-                v = genFloatMul(result, x, y, isStrictFP);
-                break;
-            case FDIV:
-            case DDIV:
-                v = genFloatDiv(result, x, y, isStrictFP);
-                break;
-            case FREM:
-            case DREM:
-                v = genFloatRem(result, x, y, isStrictFP);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(result, append(v));
-    }
-
-    protected abstract ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y);
-
-    private void genIntegerDivOp(Kind result, int opcode) {
-        ValueNode y = frameState.pop(result);
-        ValueNode x = frameState.pop(result);
-        ValueNode v;
-        switch (opcode) {
-            case IDIV:
-            case LDIV:
-                v = genIntegerDiv(result, x, y);
-                break;
-            case IREM:
-            case LREM:
-                v = genIntegerRem(result, x, y);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(result, append(v));
-    }
-
-    protected abstract ValueNode genNegateOp(ValueNode x);
-
-    private void genNegateOp(Kind kind) {
-        frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
-    }
-
-    protected abstract ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y);
-
-    private void genShiftOp(Kind kind, int opcode) {
-        ValueNode s = frameState.ipop();
-        ValueNode x = frameState.pop(kind);
-        ValueNode v;
-        switch (opcode) {
-            case ISHL:
-            case LSHL:
-                v = genLeftShift(kind, x, s);
-                break;
-            case ISHR:
-            case LSHR:
-                v = genRightShift(kind, x, s);
-                break;
-            case IUSHR:
-            case LUSHR:
-                v = genUnsignedRightShift(kind, x, s);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(kind, append(v));
-    }
-
-    protected abstract ValueNode genAnd(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genOr(Kind kind, ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genXor(Kind kind, ValueNode x, ValueNode y);
-
-    private void genLogicOp(Kind kind, int opcode) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        ValueNode v;
-        switch (opcode) {
-            case IAND:
-            case LAND:
-                v = genAnd(kind, x, y);
-                break;
-            case IOR:
-            case LOR:
-                v = genOr(kind, x, y);
-                break;
-            case IXOR:
-            case LXOR:
-                v = genXor(kind, x, y);
-                break;
-            default:
-                throw new GraalInternalError("should not reach");
-        }
-        frameState.push(kind, append(v));
-    }
-
-    protected abstract ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess);
-
-    private void genCompareOp(Kind kind, boolean isUnorderedLess) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
-    }
-
-    protected abstract ValueNode genFloatConvert(FloatConvert op, ValueNode input);
-
-    private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
-    }
-
-    protected abstract ValueNode genNarrow(ValueNode input, int bitCount);
-
-    protected abstract ValueNode genSignExtend(ValueNode input, int bitCount);
-
-    protected abstract ValueNode genZeroExtend(ValueNode input, int bitCount);
-
-    private void genSignExtend(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        if (from != from.getStackKind()) {
-            input = append(genNarrow(input, from.getBitCount()));
-        }
-        frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount())));
-    }
-
-    private void genZeroExtend(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        if (from != from.getStackKind()) {
-            input = append(genNarrow(input, from.getBitCount()));
-        }
-        frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount())));
-    }
-
-    private void genNarrow(Kind from, Kind to) {
-        ValueNode input = frameState.pop(from.getStackKind());
-        frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
-    }
-
-    private void genIncrement() {
-        int index = getStream().readLocalIndex();
-        int delta = getStream().readIncrement();
-        ValueNode x = frameState.loadLocal(index);
-        ValueNode y = appendConstant(JavaConstant.forInt(delta));
-        frameState.storeLocal(index, append(genIntegerAdd(Kind.Int, x, y)));
-    }
-
-    protected abstract void genGoto();
-
-    protected abstract ValueNode genObjectEquals(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerEquals(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genIntegerLessThan(ValueNode x, ValueNode y);
-
-    protected abstract ValueNode genUnique(ValueNode x);
-
-    protected abstract void genIf(ValueNode x, Condition cond, ValueNode y);
-
-    private void genIfZero(Condition cond) {
-        ValueNode y = appendConstant(JavaConstant.INT_0);
-        ValueNode x = frameState.ipop();
-        genIf(x, cond, y);
-    }
-
-    private void genIfNull(Condition cond) {
-        ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
-        ValueNode x = frameState.apop();
-        genIf(x, cond, y);
-    }
-
-    private void genIfSame(Kind kind, Condition cond) {
-        ValueNode y = frameState.pop(kind);
-        ValueNode x = frameState.pop(kind);
-        genIf(x, cond, y);
-    }
-
-    protected abstract void genThrow();
-
-    protected JavaType lookupType(int cpi, int bytecode) {
-        maybeEagerlyResolve(cpi, bytecode);
-        JavaType result = constantPool.lookupType(cpi, bytecode);
-        assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
-        return result;
-    }
-
-    private JavaMethod lookupMethod(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        JavaMethod result = constantPool.lookupMethod(cpi, opcode);
-        /*
-         * In general, one cannot assume that the declaring class being initialized is useful, since
-         * the actual concrete receiver may be a different class (except for static calls). Also,
-         * interfaces are initialized only under special circumstances, so that this assertion would
-         * often fail for interface calls.
-         */
-        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
-        return result;
-    }
-
-    private JavaField lookupField(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        JavaField result = constantPool.lookupField(cpi, opcode);
-        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
-        return result;
-    }
-
-    private Object lookupConstant(int cpi, int opcode) {
-        maybeEagerlyResolve(cpi, opcode);
-        Object result = constantPool.lookupConstant(cpi);
-        assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
-        return result;
-    }
-
-    private void maybeEagerlyResolve(int cpi, int bytecode) {
-        if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) {
-            constantPool.loadReferencedType(cpi, bytecode);
-        }
-    }
-
-    private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
-        if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
-            return null;
-        } else {
-            return profilingInfo.getTypeProfile(bci());
-        }
-    }
-
-    protected abstract ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck);
-
-    private void genCheckCast() {
-        int cpi = getStream().readCPI();
-        JavaType type = lookupType(cpi, CHECKCAST);
-        ValueNode object = frameState.apop();
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
-            TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
-            if (typeCheckPlugin == null || !typeCheckPlugin.checkCast((GraphBuilderContext) this, object, resolvedType, profile)) {
-                ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
-                frameState.apush(checkCastNode);
-            }
-        } else {
-            handleUnresolvedCheckCast(type, object);
-        }
-    }
-
-    protected abstract ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
-
-    protected abstract ValueNode genConditional(ValueNode x);
-
-    private void genInstanceOf() {
-        int cpi = getStream().readCPI();
-        JavaType type = lookupType(cpi, INSTANCEOF);
-        ValueNode object = frameState.apop();
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
-            TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
-            if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf((GraphBuilderContext) this, object, resolvedType, profile)) {
-                ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile);
-                frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
-            }
-        } else {
-            handleUnresolvedInstanceOf(type, object);
-        }
-    }
-
-    protected abstract ValueNode createNewInstance(ResolvedJavaType type, boolean fillContents);
-
-    void genNewInstance(int cpi) {
-        JavaType type = lookupType(cpi, NEW);
-        if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
-            ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
-            if (skippedExceptionTypes != null) {
-                for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
-                    if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
-                        append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
-                        return;
-                    }
-                }
-            }
-            frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
-        } else {
-            handleUnresolvedNewInstance(type);
-        }
-    }
-
-    /**
-     * Gets the kind of array elements for the array type code that appears in a
-     * {@link Bytecodes#NEWARRAY} bytecode.
-     *
-     * @param code the array type code
-     * @return the kind from the array type code
-     */
-    public static Class<?> arrayTypeCodeToClass(int code) {
-        // Checkstyle: stop
-        switch (code) {
-            case 4:
-                return boolean.class;
-            case 5:
-                return char.class;
-            case 6:
-                return float.class;
-            case 7:
-                return double.class;
-            case 8:
-                return byte.class;
-            case 9:
-                return short.class;
-            case 10:
-                return int.class;
-            case 11:
-                return long.class;
-            default:
-                throw new IllegalArgumentException("unknown array type code: " + code);
-        }
-        // Checkstyle: resume
-    }
-
-    private void genNewPrimitiveArray(int typeCode) {
-        Class<?> clazz = arrayTypeCodeToClass(typeCode);
-        ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
-        frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
-    }
-
-    private void genNewObjectArray(int cpi) {
-        JavaType type = lookupType(cpi, ANEWARRAY);
-        ValueNode length = frameState.ipop();
-        if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
-        } else {
-            handleUnresolvedNewObjectArray(type, length);
-        }
-
-    }
-
-    protected abstract ValueNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents);
-
-    private void genNewMultiArray(int cpi) {
-        JavaType type = lookupType(cpi, MULTIANEWARRAY);
-        int rank = getStream().readUByte(bci() + 3);
-        List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
-        for (int i = rank - 1; i >= 0; i--) {
-            dims.set(i, frameState.ipop());
-        }
-        if (type instanceof ResolvedJavaType) {
-            frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims)));
-        } else {
-            handleUnresolvedNewMultiArray(type, dims);
-        }
-    }
-
-    protected abstract ValueNode createNewMultiArray(ResolvedJavaType type, List<ValueNode> dims);
-
-    protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field);
-
-    private void genGetField(JavaField field) {
-        Kind kind = field.getKind();
-        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
-        if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
-            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
-                appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
-            }
-        } else {
-            handleUnresolvedLoadField(field, receiver);
-        }
-    }
-
-    /**
-     * Emits control flow to null check a receiver if it's stamp does not indicate it is
-     * {@linkplain StampTool#isPointerNonNull always non-null}.
-     *
-     * @return the receiver with a stamp indicating non-nullness
-     */
-    protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver);
-
-    /**
-     * Emits control flow to check an array index is within bounds of an array's length.
-     *
-     * @param index the index to check
-     * @param length the length of the array being indexed
-     */
-    protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length);
-
-    private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
-
-    protected abstract ValueNode genArrayLength(ValueNode x);
-
-    /**
-     * @param receiver the receiver of an object based operation
-     * @param index the index of an array based operation that is to be tested for out of bounds.
-     *            This is null for a non-array operation.
-     * @return the receiver value possibly modified to have a tighter stamp
-     */
-    protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
-        assert receiver != null;
-        if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null ||
-                        (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
-            return receiver;
-        }
-
-        ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
-        if (index != null) {
-            ValueNode length = append(genArrayLength(nonNullReceiver));
-            emitExplicitBoundsCheck(index, length);
-        }
-        EXPLICIT_EXCEPTIONS.increment();
-        return nonNullReceiver;
-    }
-
-    protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
-
-    private void genPutField(JavaField field) {
-        ValueNode value = frameState.pop(field.getKind().getStackKind());
-        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            genStoreField(receiver, (ResolvedJavaField) field, value);
-        } else {
-            handleUnresolvedStoreField(field, value, receiver);
-        }
-    }
-
-    private void genGetStatic(JavaField field) {
-        Kind kind = field.getKind();
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
-            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) {
-                appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field));
-            }
-        } else {
-            handleUnresolvedLoadField(field, null);
-        }
-    }
-
-    public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
-        return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
-    }
-
-    private void genPutStatic(JavaField field) {
-        ValueNode value = frameState.pop(field.getKind().getStackKind());
-        if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            genStoreField(null, (ResolvedJavaField) field, value);
-        } else {
-            handleUnresolvedStoreField(field, value, null);
-        }
-    }
-
-    protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
-        // append the load to the instruction
-        ValueNode optimized = append(load);
-        frameState.push(kind.getStackKind(), optimized);
-    }
-
-    protected abstract void genInvokeStatic(JavaMethod target);
-
-    protected abstract void genInvokeInterface(JavaMethod target);
-
-    protected abstract void genInvokeDynamic(JavaMethod target);
-
-    protected abstract void genInvokeVirtual(JavaMethod target);
-
-    protected abstract void genInvokeSpecial(JavaMethod target);
-
-    protected abstract void genReturn(ValueNode x, Kind kind);
-
-    protected abstract void genMonitorEnter(ValueNode x, int bci);
-
-    protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci);
-
-    protected abstract void genJsr(int dest);
-
-    protected abstract void genRet(int localIndex);
-
-    private double[] switchProbability(int numberOfCases, int bci) {
-        double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
-        if (prob != null) {
-            assert prob.length == numberOfCases;
-        } else {
-            Debug.log("Missing probability (switch) in %s at bci %d", method, bci);
-            prob = new double[numberOfCases];
-            for (int i = 0; i < numberOfCases; i++) {
-                prob[i] = 1.0d / numberOfCases;
-            }
-        }
-        assert allPositive(prob);
-        return prob;
-    }
-
-    private static boolean allPositive(double[] a) {
-        for (double d : a) {
-            if (d < 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Helper function that sums up the probabilities of all keys that lead to a specific successor.
-     *
-     * @return an array of size successorCount with the accumulated probability for each successor.
-     */
-    public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
-        double[] probability = new double[successorCount];
-        for (int i = 0; i < keySuccessors.length; i++) {
-            probability[keySuccessors[i]] += keyProbabilities[i];
-        }
-        return probability;
-    }
-
-    private void genSwitch(BytecodeSwitch bs) {
-        int bci = bci();
-        ValueNode value = frameState.ipop();
-
-        int nofCases = bs.numberOfCases();
-        double[] keyProbabilities = switchProbability(nofCases + 1, bci);
-
-        Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
-        for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
-            assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
-            if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
-                bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
-            }
-        }
-
-        ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
-        int[] keys = new int[nofCases];
-        int[] keySuccessors = new int[nofCases + 1];
-        int deoptSuccessorIndex = -1;
-        int nextSuccessorIndex = 0;
-        boolean constantValue = value.isConstant();
-        for (int i = 0; i < nofCases + 1; i++) {
-            if (i < nofCases) {
-                keys[i] = bs.keyAt(i);
-            }
-
-            if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
-                if (deoptSuccessorIndex < 0) {
-                    deoptSuccessorIndex = nextSuccessorIndex++;
-                    actualSuccessors.add(null);
-                }
-                keySuccessors[i] = deoptSuccessorIndex;
-            } else {
-                int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i);
-                SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
-                if (info.actualIndex < 0) {
-                    info.actualIndex = nextSuccessorIndex++;
-                    actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
-                }
-                keySuccessors[i] = info.actualIndex;
-            }
-        }
-
-        genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors);
-
-    }
-
-    protected abstract void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors);
-
-    private static class SuccessorInfo {
-
-        int blockIndex;
-        int actualIndex;
-
-        public SuccessorInfo(int blockSuccessorIndex) {
-            this.blockIndex = blockSuccessorIndex;
-            actualIndex = -1;
-        }
-    }
-
-    protected abstract ValueNode appendConstant(JavaConstant constant);
-
-    protected abstract <T extends ValueNode> T append(T v);
-
-    protected boolean isNeverExecutedCode(double probability) {
-        return probability == 0 && optimisticOpts.removeNeverExecutedCode();
-    }
-
-    protected double branchProbability() {
-        if (profilingInfo == null) {
-            return 0.5;
-        }
-        assert assertAtIfBytecode();
-        double probability = profilingInfo.getBranchTakenProbability(bci());
-        if (probability < 0) {
-            assert probability == -1 : "invalid probability";
-            Debug.log("missing probability in %s at bci %d", method, bci());
-            probability = 0.5;
-        }
-
-        if (!optimisticOpts.removeNeverExecutedCode()) {
-            if (probability == 0) {
-                probability = 0.0000001;
-            } else if (probability == 1) {
-                probability = 0.999999;
-            }
-        }
-        return probability;
-    }
-
-    private boolean assertAtIfBytecode() {
-        int bytecode = stream.currentBC();
-        switch (bytecode) {
-            case IFEQ:
-            case IFNE:
-            case IFLT:
-            case IFGE:
-            case IFGT:
-            case IFLE:
-            case IF_ICMPEQ:
-            case IF_ICMPNE:
-            case IF_ICMPLT:
-            case IF_ICMPGE:
-            case IF_ICMPGT:
-            case IF_ICMPLE:
-            case IF_ACMPEQ:
-            case IF_ACMPNE:
-            case IFNULL:
-            case IFNONNULL:
-                return true;
-        }
-        assert false : String.format("%x is not an if bytecode", bytecode);
-        return true;
-    }
-
-    protected abstract void iterateBytecodesForBlock(BciBlock block);
-
-    public final void processBytecode(int bci, int opcode) {
-        int cpi;
-
-        // Checkstyle: stop
-        // @formatter:off
-        switch (opcode) {
-            case NOP            : /* nothing to do */ break;
-            case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
-            case ICONST_M1      : // fall through
-            case ICONST_0       : // fall through
-            case ICONST_1       : // fall through
-            case ICONST_2       : // fall through
-            case ICONST_3       : // fall through
-            case ICONST_4       : // fall through
-            case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
-            case LCONST_0       : // fall through
-            case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
-            case FCONST_0       : // fall through
-            case FCONST_1       : // fall through
-            case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
-            case DCONST_0       : // fall through
-            case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
-            case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
-            case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
-            case LDC            : // fall through
-            case LDC_W          : // fall through
-            case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
-            case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
-            case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
-            case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
-            case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
-            case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
-            case ILOAD_0        : // fall through
-            case ILOAD_1        : // fall through
-            case ILOAD_2        : // fall through
-            case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
-            case LLOAD_0        : // fall through
-            case LLOAD_1        : // fall through
-            case LLOAD_2        : // fall through
-            case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
-            case FLOAD_0        : // fall through
-            case FLOAD_1        : // fall through
-            case FLOAD_2        : // fall through
-            case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
-            case DLOAD_0        : // fall through
-            case DLOAD_1        : // fall through
-            case DLOAD_2        : // fall through
-            case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
-            case ALOAD_0        : // fall through
-            case ALOAD_1        : // fall through
-            case ALOAD_2        : // fall through
-            case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
-            case IALOAD         : genLoadIndexed(Kind.Int   ); break;
-            case LALOAD         : genLoadIndexed(Kind.Long  ); break;
-            case FALOAD         : genLoadIndexed(Kind.Float ); break;
-            case DALOAD         : genLoadIndexed(Kind.Double); break;
-            case AALOAD         : genLoadIndexed(Kind.Object); break;
-            case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
-            case CALOAD         : genLoadIndexed(Kind.Char  ); break;
-            case SALOAD         : genLoadIndexed(Kind.Short ); break;
-            case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
-            case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
-            case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
-            case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
-            case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
-            case ISTORE_0       : // fall through
-            case ISTORE_1       : // fall through
-            case ISTORE_2       : // fall through
-            case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
-            case LSTORE_0       : // fall through
-            case LSTORE_1       : // fall through
-            case LSTORE_2       : // fall through
-            case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
-            case FSTORE_0       : // fall through
-            case FSTORE_1       : // fall through
-            case FSTORE_2       : // fall through
-            case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
-            case DSTORE_0       : // fall through
-            case DSTORE_1       : // fall through
-            case DSTORE_2       : // fall through
-            case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
-            case ASTORE_0       : // fall through
-            case ASTORE_1       : // fall through
-            case ASTORE_2       : // fall through
-            case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
-            case IASTORE        : genStoreIndexed(Kind.Int   ); break;
-            case LASTORE        : genStoreIndexed(Kind.Long  ); break;
-            case FASTORE        : genStoreIndexed(Kind.Float ); break;
-            case DASTORE        : genStoreIndexed(Kind.Double); break;
-            case AASTORE        : genStoreIndexed(Kind.Object); break;
-            case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
-            case CASTORE        : genStoreIndexed(Kind.Char  ); break;
-            case SASTORE        : genStoreIndexed(Kind.Short ); break;
-            case POP            : frameState.xpop(); break;
-            case POP2           : frameState.xpop(); frameState.xpop(); break;
-            case DUP            : frameState.xpush(frameState.xpeek()); break;
-            case DUP_X1         : // fall through
-            case DUP_X2         : // fall through
-            case DUP2           : // fall through
-            case DUP2_X1        : // fall through
-            case DUP2_X2        : // fall through
-            case SWAP           : stackOp(opcode); break;
-            case IADD           : // fall through
-            case ISUB           : // fall through
-            case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
-            case IDIV           : // fall through
-            case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
-            case LADD           : // fall through
-            case LSUB           : // fall through
-            case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
-            case LDIV           : // fall through
-            case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
-            case FADD           : // fall through
-            case FSUB           : // fall through
-            case FMUL           : // fall through
-            case FDIV           : // fall through
-            case FREM           : genArithmeticOp(Kind.Float, opcode); break;
-            case DADD           : // fall through
-            case DSUB           : // fall through
-            case DMUL           : // fall through
-            case DDIV           : // fall through
-            case DREM           : genArithmeticOp(Kind.Double, opcode); break;
-            case INEG           : genNegateOp(Kind.Int); break;
-            case LNEG           : genNegateOp(Kind.Long); break;
-            case FNEG           : genNegateOp(Kind.Float); break;
-            case DNEG           : genNegateOp(Kind.Double); break;
-            case ISHL           : // fall through
-            case ISHR           : // fall through
-            case IUSHR          : genShiftOp(Kind.Int, opcode); break;
-            case IAND           : // fall through
-            case IOR            : // fall through
-            case IXOR           : genLogicOp(Kind.Int, opcode); break;
-            case LSHL           : // fall through
-            case LSHR           : // fall through
-            case LUSHR          : genShiftOp(Kind.Long, opcode); break;
-            case LAND           : // fall through
-            case LOR            : // fall through
-            case LXOR           : genLogicOp(Kind.Long, opcode); break;
-            case IINC           : genIncrement(); break;
-            case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
-            case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
-            case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
-            case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
-            case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
-            case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
-            case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
-            case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
-            case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
-            case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
-            case L2I            : genNarrow(Kind.Long, Kind.Int); break;
-            case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
-            case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
-            case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
-            case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
-            case LCMP           : genCompareOp(Kind.Long, false); break;
-            case FCMPL          : genCompareOp(Kind.Float, true); break;
-            case FCMPG          : genCompareOp(Kind.Float, false); break;
-            case DCMPL          : genCompareOp(Kind.Double, true); break;
-            case DCMPG          : genCompareOp(Kind.Double, false); break;
-            case IFEQ           : genIfZero(Condition.EQ); break;
-            case IFNE           : genIfZero(Condition.NE); break;
-            case IFLT           : genIfZero(Condition.LT); break;
-            case IFGE           : genIfZero(Condition.GE); break;
-            case IFGT           : genIfZero(Condition.GT); break;
-            case IFLE           : genIfZero(Condition.LE); break;
-            case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
-            case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
-            case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
-            case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
-            case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
-            case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
-            case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
-            case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
-            case GOTO           : genGoto(); break;
-            case JSR            : genJsr(stream.readBranchDest()); break;
-            case RET            : genRet(stream.readLocalIndex()); break;
-            case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
-            case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
-            case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
-            case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
-            case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
-            case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
-            case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
-            case RETURN         : genReturn(null, Kind.Void); break;
-            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
-            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
-            case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
-            case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
-            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
-            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
-            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
-            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
-            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
-            case NEW            : genNewInstance(stream.readCPI()); break;
-            case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
-            case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
-            case ARRAYLENGTH    : genArrayLength(); break;
-            case ATHROW         : genThrow(); break;
-            case CHECKCAST      : genCheckCast(); break;
-            case INSTANCEOF     : genInstanceOf(); break;
-            case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
-            case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
-            case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
-            case IFNULL         : genIfNull(Condition.EQ); break;
-            case IFNONNULL      : genIfNull(Condition.NE); break;
-            case GOTO_W         : genGoto(); break;
-            case JSR_W          : genJsr(stream.readBranchDest()); break;
-            case BREAKPOINT:
-                throw new BailoutException("concurrent setting of breakpoint");
-            default:
-                throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
-        }
-        // @formatter:on
-        // Checkstyle: resume
-    }
-
-    private void genArrayLength() {
-        frameState.ipush(append(genArrayLength(frameState.apop())));
-    }
-
-    public ResolvedJavaMethod getMethod() {
-        return method;
-    }
-
-    public HIRFrameStateBuilder getFrameState() {
-        return frameState;
-    }
-
-    protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
-        if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
-            traceInstructionHelper(bci, opcode, blockStart);
-        }
-        return true;
-    }
-
-    private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
-        StringBuilder sb = new StringBuilder(40);
-        sb.append(blockStart ? '+' : '|');
-        if (bci < 10) {
-            sb.append("  ");
-        } else if (bci < 100) {
-            sb.append(' ');
-        }
-        sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode));
-        for (int i = bci + 1; i < stream.nextBCI(); ++i) {
-            sb.append(' ').append(stream.readUByte(i));
-        }
-        if (!currentBlock.getJsrScope().isEmpty()) {
-            sb.append(' ').append(currentBlock.getJsrScope());
-        }
-        Debug.log("%s", sb);
-    }
-
-    public boolean parsingIntrinsic() {
-        return intrinsicContext != null;
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,451 +0,0 @@
-/*
- * Copyright (c) 2014, 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.java;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-
-public abstract class AbstractFrameStateBuilder<T extends KindProvider, S extends AbstractFrameStateBuilder<T, S>> {
-
-    protected final ResolvedJavaMethod method;
-    protected int stackSize;
-    protected final T[] locals;
-    protected final T[] stack;
-    protected T[] lockedObjects;
-
-    protected final BytecodeParser parser;
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    protected boolean rethrowException;
-
-    public AbstractFrameStateBuilder(ResolvedJavaMethod method, BytecodeParser parser) {
-        this.method = method;
-        this.parser = parser;
-        this.locals = allocateArray(method.getMaxLocals());
-        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
-        this.lockedObjects = allocateArray(0);
-    }
-
-    protected AbstractFrameStateBuilder(S other) {
-        this.method = other.method;
-        this.parser = other.parser;
-        this.stackSize = other.stackSize;
-        this.locals = other.locals.clone();
-        this.stack = other.stack.clone();
-        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
-        this.rethrowException = other.rethrowException;
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-    }
-
-    public abstract S copy();
-
-    protected abstract T[] allocateArray(int length);
-
-    public abstract boolean isCompatibleWith(S other);
-
-    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
-        /*
-         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
-         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
-         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
-         * Kind.Illegal, because the conflicting branch might not have been parsed.
-         */
-        if (liveness == null) {
-            return;
-        }
-        if (liveIn) {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveIn(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        } else {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveOut(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        }
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public boolean rethrowException() {
-        return rethrowException;
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public void setRethrowException(boolean b) {
-        rethrowException = b;
-    }
-
-    /**
-     * Returns the size of the local variables.
-     *
-     * @return the size of the local variables
-     */
-    public int localsSize() {
-        return locals.length;
-    }
-
-    /**
-     * Gets the current size (height) of the stack.
-     */
-    public int stackSize() {
-        return stackSize;
-    }
-
-    /**
-     * @return the current lock depth
-     */
-    public int lockDepth() {
-        return lockedObjects.length;
-    }
-
-    /**
-     * Gets the value in the local variables at the specified index, without any sanity checking.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public T localAt(int i) {
-        return locals[i];
-    }
-
-    /**
-     * Get the value on the stack at the specified stack index.
-     *
-     * @param i the index into the stack, with {@code 0} being the bottom of the stack
-     * @return the instruction at the specified position in the stack
-     */
-    public T stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * Gets the value in the lock at the specified index, without any sanity checking.
-     *
-     * @param i the index into the lock
-     * @return the instruction that produced the value for the specified lock
-     */
-    public T lockAt(int i) {
-        return lockedObjects[i];
-    }
-
-    public void storeLock(int i, T lock) {
-        lockedObjects[i] = lock;
-    }
-
-    /**
-     * Loads the local variable at the specified index, checking that the returned value is non-null
-     * and that two-stack values are properly handled.
-     *
-     * @param i the index of the local variable to load
-     * @return the instruction that produced the specified local
-     */
-    public T loadLocal(int i) {
-        T x = locals[i];
-        assert x != null : i;
-        assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
-        return x;
-    }
-
-    public void storeLocal(int i, T x) {
-        storeLocal(i, x, x == null ? null : x.getKind());
-    }
-
-    /**
-     * Stores a given local variable at the specified index. If the value occupies two slots, then
-     * the next local variable index is also overwritten.
-     *
-     * @param i the index at which to store
-     * @param x the instruction which produces the value for the local
-     */
-    public void storeLocal(int i, T x, Kind kind) {
-        assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
-        locals[i] = x;
-        if (x != null) {
-            if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) {
-                // if this is a double word, then kill i+1
-                locals[i + 1] = null;
-            }
-            if (i > 0 && !parser.parsingIntrinsic()) {
-                T p = locals[i - 1];
-                if (p != null && p.getKind().needsTwoSlots()) {
-                    // if there was a double word at i - 1, then kill it
-                    locals[i - 1] = null;
-                }
-            }
-        }
-    }
-
-    public void storeStack(int i, T x) {
-        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
-        stack[i] = x;
-    }
-
-    /**
-     * Pushes an instruction onto the stack with the expected type.
-     *
-     * @param kind the type expected for this instruction
-     * @param x the instruction to push onto the stack
-     */
-    public void push(Kind kind, T x) {
-        assert kind != Kind.Void && kind != Kind.Illegal : kind + ":" + x;
-        xpush(assertKind(kind, x));
-        if (kind.needsTwoSlots()) {
-            xpush(null);
-        }
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(T x) {
-        assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
-        stack[stackSize++] = x;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(T x) {
-        xpush(assertInt(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(T x) {
-        xpush(assertFloat(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(T x) {
-        xpush(assertObject(x));
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(T x) {
-        xpush(assertLong(x));
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(T x) {
-        xpush(assertDouble(x));
-        xpush(null);
-    }
-
-    public void pushReturn(Kind kind, T x) {
-        if (kind != Kind.Void) {
-            push(kind.getStackKind(), x);
-        }
-    }
-
-    /**
-     * Pops an instruction off the stack with the expected type.
-     *
-     * @param kind the expected type
-     * @return the instruction on the top of the stack
-     */
-    public T pop(Kind kind) {
-        assert kind != Kind.Void;
-        if (kind.needsTwoSlots()) {
-            xpop();
-        }
-        return assertKind(kind, xpop());
-    }
-
-    /**
-     * Pops a value off of the stack without checking the type.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T xpop() {
-        T result = stack[--stackSize];
-        return result;
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an int.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T ipop() {
-        return assertInt(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T fpop() {
-        return assertFloat(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T apop() {
-        return assertObject(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T lpop() {
-        assertHigh(xpop());
-        return assertLong(xpop());
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public T dpop() {
-        assertHigh(xpop());
-        return assertDouble(xpop());
-    }
-
-    /**
-     * Pop the specified number of slots off of this stack and return them as an array of
-     * instructions.
-     *
-     * @return an array containing the arguments off of the stack
-     */
-    public T[] popArguments(int argSize) {
-        T[] result = allocateArray(argSize);
-        int newStackSize = stackSize;
-        for (int i = argSize - 1; i >= 0; i--) {
-            newStackSize--;
-            if (stack[newStackSize] == null) {
-                /* Two-slot value. */
-                newStackSize--;
-                assert stack[newStackSize].getKind().needsTwoSlots();
-            } else {
-                assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1);
-            }
-            result[i] = stack[newStackSize];
-        }
-        stackSize = newStackSize;
-        return result;
-    }
-
-    /**
-     * Peeks an element from the operand stack.
-     *
-     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
-     *            top). Long and double arguments only count as one argument, i.e., null-slots are
-     *            ignored.
-     * @return The peeked argument.
-     */
-    public T peek(int argumentNumber) {
-        int idx = stackSize() - 1;
-        for (int i = 0; i < argumentNumber; i++) {
-            if (stackAt(idx) == null) {
-                idx--;
-                assert stackAt(idx).getKind().needsTwoSlots();
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackSize = 0;
-    }
-
-    private T assertKind(Kind kind, T x) {
-        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
-        return x;
-    }
-
-    private T assertLong(T x) {
-        assert x != null && (x.getKind() == Kind.Long);
-        return x;
-    }
-
-    private T assertInt(T x) {
-        assert x != null && (x.getKind() == Kind.Int);
-        return x;
-    }
-
-    private T assertFloat(T x) {
-        assert x != null && (x.getKind() == Kind.Float);
-        return x;
-    }
-
-    private T assertObject(T x) {
-        assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object));
-        return x;
-    }
-
-    private T assertDouble(T x) {
-        assert x != null && (x.getKind() == Kind.Double);
-        return x;
-    }
-
-    private void assertHigh(T x) {
-        assert x == null;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.IntrinsicContext.SideEffectsState;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
+
+public final class FrameStateBuilder implements SideEffectsState {
+
+    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+
+    protected final BytecodeParser parser;
+    protected final ResolvedJavaMethod method;
+    protected int stackSize;
+    protected final ValueNode[] locals;
+    protected final ValueNode[] stack;
+    protected ValueNode[] lockedObjects;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    protected boolean rethrowException;
+
+    private MonitorIdNode[] monitorIds;
+    private final StructuredGraph graph;
+    private FrameState outerFrameState;
+
+    /**
+     * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
+     * than one when the current block contains no side-effects but merging predecessor blocks do.
+     */
+    protected List<StateSplit> sideEffects;
+
+    /**
+     * Creates a new frame state builder for the given method and the given target graph.
+     *
+     * @param method the method whose frame is simulated
+     * @param graph the target graph of Graal nodes created by the builder
+     */
+    public FrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) {
+        this.parser = parser;
+        this.method = method;
+        this.locals = allocateArray(method.getMaxLocals());
+        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
+        this.lockedObjects = allocateArray(0);
+
+        assert graph != null;
+
+        this.monitorIds = EMPTY_MONITOR_ARRAY;
+        this.graph = graph;
+    }
+
+    public void initializeFromArgumentsArray(ValueNode[] arguments) {
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // set the receiver
+            locals[javaIndex] = arguments[index];
+            javaIndex = 1;
+            index = 1;
+        }
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        for (int i = 0; i < max; i++) {
+            Kind kind = sig.getParameterKind(i);
+            locals[javaIndex] = arguments[index];
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
+
+        int javaIndex = 0;
+        int index = 0;
+        if (!method.isStatic()) {
+            // add the receiver
+            FloatingNode receiver = null;
+            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
+            if (parameterPlugin != null) {
+                receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp);
+            }
+            if (receiver == null) {
+                receiver = new ParameterNode(javaIndex, receiverStamp);
+            }
+            locals[javaIndex] = graph.unique(receiver);
+            javaIndex = 1;
+            index = 1;
+        }
+        Signature sig = method.getSignature();
+        int max = sig.getParameterCount(false);
+        ResolvedJavaType accessingClass = method.getDeclaringClass();
+        for (int i = 0; i < max; i++) {
+            JavaType type = sig.getParameterType(i, accessingClass);
+            if (eagerResolve) {
+                type = type.resolve(accessingClass);
+            }
+            Kind kind = type.getKind();
+            Stamp stamp;
+            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
+                stamp = StampFactory.declared((ResolvedJavaType) type);
+            } else {
+                stamp = StampFactory.forKind(kind);
+            }
+            FloatingNode param = null;
+            if (parameterPlugin != null) {
+                param = parameterPlugin.interceptParameter(parser, index, stamp);
+            }
+            if (param == null) {
+                param = new ParameterNode(index, stamp);
+            }
+            locals[javaIndex] = graph.unique(param);
+            javaIndex += kind.getSlotCount();
+            index++;
+        }
+    }
+
+    private FrameStateBuilder(FrameStateBuilder other) {
+        this.parser = other.parser;
+        this.method = other.method;
+        this.stackSize = other.stackSize;
+        this.locals = other.locals.clone();
+        this.stack = other.stack.clone();
+        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
+        this.rethrowException = other.rethrowException;
+
+        assert locals.length == method.getMaxLocals();
+        assert stack.length == Math.max(1, method.getMaxStackSize());
+
+        assert other.graph != null;
+        graph = other.graph;
+        monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
+
+        assert locals.length == method.getMaxLocals();
+        assert stack.length == Math.max(1, method.getMaxStackSize());
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    private static ValueNode[] allocateArray(int length) {
+        return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[locals: [");
+        for (int i = 0; i < locals.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id));
+        }
+        sb.append("] stack: [");
+        for (int i = 0; i < stackSize; i++) {
+            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
+        }
+        sb.append("] locks: [");
+        for (int i = 0; i < lockedObjects.length; i++) {
+            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
+        }
+        sb.append("]");
+        if (rethrowException) {
+            sb.append(" rethrowException");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public FrameState create(int bci, StateSplit forStateSplit) {
+        if (parser.parsingIntrinsic()) {
+            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit);
+        }
+
+        // Skip intrinsic frames
+        return create(bci, parser.getNonIntrinsicAncestor(), false, (ValueNode[]) null);
+    }
+
+    /**
+     * @param pushedValues if non-null, values to {@link #push(Kind, ValueNode)} to the stack before
+     *            creating the {@link FrameState}
+     */
+    public FrameState create(int bci, BytecodeParser parent, boolean duringCall, ValueNode... pushedValues) {
+        if (outerFrameState == null && parent != null) {
+            outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), null);
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
+            return newFrameState;
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        if (pushedValues != null) {
+            int stackSizeToRestore = stackSize;
+            for (ValueNode arg : pushedValues) {
+                push(arg.getKind(), arg);
+            }
+            FrameState res = graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+            stackSize = stackSizeToRestore;
+            return res;
+        } else {
+            return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
+        }
+    }
+
+    public BytecodePosition createBytecodePosition(int bci) {
+        BytecodeParser parent = parser.getParent();
+        if (HideSubstitutionStates.getValue()) {
+            if (parser.parsingIntrinsic()) {
+                // Attribute to the method being replaced
+                return new BytecodePosition(parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
+            }
+            // Skip intrinsic frames
+            parent = parser.getNonIntrinsicAncestor();
+        }
+        return create(null, bci, parent);
+    }
+
+    private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) {
+        BytecodePosition outer = o;
+        if (outer == null && parent != null) {
+            outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
+        }
+        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
+            return FrameState.toBytecodePosition(outerFrameState);
+        }
+        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+        return new BytecodePosition(outer, method, bci);
+    }
+
+    public FrameStateBuilder copy() {
+        return new FrameStateBuilder(this);
+    }
+
+    public boolean isCompatibleWith(FrameStateBuilder other) {
+        assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
+        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
+
+        if (stackSize() != other.stackSize()) {
+            return false;
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode x = stackAt(i);
+            ValueNode y = other.stackAt(i);
+            if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) {
+                return false;
+            }
+        }
+        if (lockedObjects.length != other.lockedObjects.length) {
+            return false;
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
+                throw new BailoutException("unbalanced monitors");
+            }
+        }
+        return true;
+    }
+
+    public void merge(AbstractMergeNode block, FrameStateBuilder other) {
+        assert isCompatibleWith(other);
+
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode curLocal = localAt(i);
+            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
+            if (curLocal != mergedLocal) {
+                storeLocal(i, mergedLocal);
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode curStack = stackAt(i);
+            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
+            if (curStack != mergedStack) {
+                storeStack(i, mergedStack);
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
+            assert monitorIds[i] == other.monitorIds[i];
+        }
+
+        if (sideEffects == null) {
+            sideEffects = other.sideEffects;
+        } else {
+            if (other.sideEffects != null) {
+                sideEffects.addAll(other.sideEffects);
+            }
+        }
+    }
+
+    private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        if (currentValue == null || currentValue.isDeleted()) {
+            return null;
+        } else if (block.isPhiAtMerge(currentValue)) {
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                propagateDelete((ValuePhiNode) currentValue);
+                return null;
+            }
+            ((PhiNode) currentValue).addInput(otherValue);
+            return currentValue;
+        } else if (currentValue != otherValue) {
+            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
+            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
+                return null;
+            }
+            return createValuePhi(currentValue, otherValue, block);
+        } else {
+            return currentValue;
+        }
+    }
+
+    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
+        for (int i = 0; i < block.phiPredecessorCount(); i++) {
+            phi.addInput(currentValue);
+        }
+        phi.addInput(otherValue);
+        assert phi.valueCount() == block.phiPredecessorCount() + 1;
+        return phi;
+    }
+
+    private void propagateDelete(FloatingNode node) {
+        assert node instanceof ValuePhiNode || node instanceof ProxyNode;
+        if (node.isDeleted()) {
+            return;
+        }
+        // Collect all phi functions that use this phi so that we can delete them recursively (after
+        // we delete ourselves to avoid circles).
+        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot();
+
+        // Remove the phi function from all FrameStates where it is used and then delete it.
+        assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
+        node.replaceAtUsages(null);
+        node.safeDelete();
+
+        for (FloatingNode phiUsage : propagateUsages) {
+            propagateDelete(phiUsage);
+        }
+    }
+
+    public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis) {
+        for (int i = 0; i < localsSize(); i++) {
+            boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i);
+            if (changedInLoop || forcePhis) {
+                storeLocal(i, createLoopPhi(loopBegin, localAt(i), !changedInLoop));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            storeStack(i, createLoopPhi(loopBegin, stackAt(i), false));
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false);
+        }
+    }
+
+    public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = localAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stackAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
+            }
+        }
+    }
+
+    public void insertProxies(AbstractBeginNode begin) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = localAt(i);
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                storeLocal(i, ProxyNode.forValue(value, begin, graph));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stackAt(i);
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                storeStack(i, ProxyNode.forValue(value, begin, graph));
+            }
+        }
+        for (int i = 0; i < lockedObjects.length; i++) {
+            ValueNode value = lockedObjects[i];
+            if (value != null) {
+                Debug.log(" inserting proxy for %s", value);
+                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
+            }
+        }
+    }
+
+    private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) {
+        if (value == null) {
+            return null;
+        }
+        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
+
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block));
+        phi.addInput(value);
+        return phi;
+    }
+
+    /**
+     * Adds a locked monitor to this frame state.
+     *
+     * @param object the object whose monitor will be locked.
+     */
+    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
+        assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object;
+        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
+        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
+        lockedObjects[lockedObjects.length - 1] = object;
+        monitorIds[monitorIds.length - 1] = monitorId;
+        assert lockedObjects.length == monitorIds.length;
+    }
+
+    /**
+     * Removes a locked monitor from this frame state.
+     *
+     * @return the object whose monitor was removed from the locks list.
+     */
+    public ValueNode popLock() {
+        try {
+            return lockedObjects[lockedObjects.length - 1];
+        } finally {
+            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
+            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
+            assert lockedObjects.length == monitorIds.length;
+        }
+    }
+
+    public MonitorIdNode peekMonitorId() {
+        return monitorIds[monitorIds.length - 1];
+    }
+
+    /**
+     * @return the current lock depth
+     */
+    public int lockDepth() {
+        assert lockedObjects.length == monitorIds.length;
+        return lockedObjects.length;
+    }
+
+    public boolean contains(ValueNode value) {
+        for (int i = 0; i < localsSize(); i++) {
+            if (localAt(i) == value) {
+                return true;
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (stackAt(i) == value) {
+                return true;
+            }
+        }
+        assert lockedObjects.length == monitorIds.length;
+        for (int i = 0; i < lockedObjects.length; i++) {
+            if (lockedObjects[i] == value || monitorIds[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
+        if (!parser.graphBuilderConfig.clearNonLiveLocals()) {
+            return;
+        }
+        if (liveIn) {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveIn(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        } else {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveOut(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public boolean rethrowException() {
+        return rethrowException;
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public void setRethrowException(boolean b) {
+        rethrowException = b;
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public int localsSize() {
+        return locals.length;
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackSize;
+    }
+
+    /**
+     * Gets the value in the local variables at the specified index, without any sanity checking.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public ValueNode localAt(int i) {
+        return locals[i];
+    }
+
+    /**
+     * Get the value on the stack at the specified stack index.
+     *
+     * @param i the index into the stack, with {@code 0} being the bottom of the stack
+     * @return the instruction at the specified position in the stack
+     */
+    public ValueNode stackAt(int i) {
+        return stack[i];
+    }
+
+    /**
+     * Gets the value in the lock at the specified index, without any sanity checking.
+     *
+     * @param i the index into the lock
+     * @return the instruction that produced the value for the specified lock
+     */
+    public ValueNode lockAt(int i) {
+        return lockedObjects[i];
+    }
+
+    public void storeLock(int i, ValueNode lock) {
+        lockedObjects[i] = lock;
+    }
+
+    /**
+     * Loads the local variable at the specified index, checking that the returned value is non-null
+     * and that two-stack values are properly handled.
+     *
+     * @param i the index of the local variable to load
+     * @return the instruction that produced the specified local
+     */
+    public ValueNode loadLocal(int i) {
+        ValueNode x = locals[i];
+        assert assertLoadLocal(i, x);
+        return x;
+    }
+
+    private boolean assertLoadLocal(int i, ValueNode x) {
+        assert x != null : i;
+        assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
+        return true;
+    }
+
+    public void storeLocal(int i, ValueNode x) {
+        storeLocal(i, x, x == null ? null : x.getKind());
+    }
+
+    /**
+     * Stores a given local variable at the specified index. If the value occupies two slots, then
+     * the next local variable index is also overwritten.
+     *
+     * @param i the index at which to store
+     * @param x the instruction which produces the value for the local
+     */
+    public void storeLocal(int i, ValueNode x, Kind kind) {
+        assert assertStoreLocal(x);
+        locals[i] = x;
+        if (x != null) {
+            if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) {
+                // if this is a double word, then kill i+1
+                locals[i + 1] = null;
+            }
+            if (i > 0 && !parser.parsingIntrinsic()) {
+                ValueNode p = locals[i - 1];
+                if (p != null && p.getKind().needsTwoSlots()) {
+                    // if there was a double word at i - 1, then kill it
+                    locals[i - 1] = null;
+                }
+            }
+        }
+    }
+
+    private boolean assertStoreLocal(ValueNode x) {
+        assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
+        return true;
+    }
+
+    public void storeStack(int i, ValueNode x) {
+        assert assertStoreStack(i, x);
+        stack[i] = x;
+    }
+
+    private boolean assertStoreStack(int i, ValueNode x) {
+        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
+        return true;
+    }
+
+    /**
+     * Pushes an instruction onto the stack with the expected type.
+     *
+     * @param kind the type expected for this instruction
+     * @param x the instruction to push onto the stack
+     */
+    public void push(Kind kind, ValueNode x) {
+        assert assertPush(kind, x);
+        xpush(x);
+        if (kind.needsTwoSlots()) {
+            xpush(null);
+        }
+    }
+
+    private boolean assertPush(Kind kind, ValueNode x) {
+        assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack without checking the type.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void xpush(ValueNode x) {
+        assert assertXpush(x);
+        stack[stackSize++] = x;
+    }
+
+    private boolean assertXpush(ValueNode x) {
+        assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an int.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void ipush(ValueNode x) {
+        assert assertInt(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a float.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void fpush(ValueNode x) {
+        assert assertFloat(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an object.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void apush(ValueNode x) {
+        assert assertObject(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a long.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void lpush(ValueNode x) {
+        assert assertLong(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a double.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void dpush(ValueNode x) {
+        assert assertDouble(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    public void pushReturn(Kind kind, ValueNode x) {
+        if (kind != Kind.Void) {
+            push(kind.getStackKind(), x);
+        }
+    }
+
+    /**
+     * Pops an instruction off the stack with the expected type.
+     *
+     * @param kind the expected type
+     * @return the instruction on the top of the stack
+     */
+    public ValueNode pop(Kind kind) {
+        if (kind.needsTwoSlots()) {
+            xpop();
+        }
+        assert assertPop(kind);
+        return xpop();
+    }
+
+    private boolean assertPop(Kind kind) {
+        assert kind != Kind.Void;
+        ValueNode x = xpeek();
+        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pops a value off of the stack without checking the type.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode xpop() {
+        return stack[--stackSize];
+    }
+
+    public ValueNode xpeek() {
+        return stack[stackSize - 1];
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an int.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode ipop() {
+        assert assertIntPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a float.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode fpop() {
+        assert assertFloatPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an object.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode apop() {
+        assert assertObjectPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a long.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode lpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertLongPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a double.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode dpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertDoublePeek();
+        return xpop();
+    }
+
+    /**
+     * Pop the specified number of slots off of this stack and return them as an array of
+     * instructions.
+     *
+     * @return an array containing the arguments off of the stack
+     */
+    public ValueNode[] popArguments(int argSize) {
+        ValueNode[] result = allocateArray(argSize);
+        int newStackSize = stackSize;
+        for (int i = argSize - 1; i >= 0; i--) {
+            newStackSize--;
+            if (stack[newStackSize] == null) {
+                /* Two-slot value. */
+                newStackSize--;
+                assert stack[newStackSize].getKind().needsTwoSlots();
+            } else {
+                assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1);
+            }
+            result[i] = stack[newStackSize];
+        }
+        stackSize = newStackSize;
+        return result;
+    }
+
+    /**
+     * Peeks an element from the operand stack.
+     *
+     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
+     *            top). Long and double arguments only count as one argument, i.e., null-slots are
+     *            ignored.
+     * @return The peeked argument.
+     */
+    public ValueNode peek(int argumentNumber) {
+        int idx = stackSize() - 1;
+        for (int i = 0; i < argumentNumber; i++) {
+            if (stackAt(idx) == null) {
+                idx--;
+                assert stackAt(idx).getKind().needsTwoSlots();
+            }
+            idx--;
+        }
+        return stackAt(idx);
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackSize = 0;
+    }
+
+    private boolean assertLongPeek() {
+        return assertLong(xpeek());
+    }
+
+    private static boolean assertLong(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Long);
+        return true;
+    }
+
+    private boolean assertIntPeek() {
+        return assertInt(xpeek());
+    }
+
+    private static boolean assertInt(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Int);
+        return true;
+    }
+
+    private boolean assertFloatPeek() {
+        return assertFloat(xpeek());
+    }
+
+    private static boolean assertFloat(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Float);
+        return true;
+    }
+
+    private boolean assertObjectPeek() {
+        return assertObject(xpeek());
+    }
+
+    private boolean assertObject(ValueNode x) {
+        assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object));
+        return true;
+    }
+
+    private boolean assertDoublePeek() {
+        return assertDouble(xpeek());
+    }
+
+    private static boolean assertDouble(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Double);
+        return true;
+    }
+
+    private boolean assertHighPeek() {
+        assert xpeek() == null;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = hashCode(locals, locals.length);
+        result *= 13;
+        result += hashCode(stack, this.stackSize);
+        return result;
+    }
+
+    private static int hashCode(Object[] a, int length) {
+        int result = 1;
+        for (int i = 0; i < length; ++i) {
+            Object element = a[i];
+            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
+        }
+        return result;
+    }
+
+    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
+        for (int i = 0; i < length; ++i) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object otherObject) {
+        if (otherObject instanceof FrameStateBuilder) {
+            FrameStateBuilder other = (FrameStateBuilder) otherObject;
+            if (!other.method.equals(method)) {
+                return false;
+            }
+            if (other.stackSize != stackSize) {
+                return false;
+            }
+            if (other.parser != parser) {
+                return false;
+            }
+            if (other.rethrowException != rethrowException) {
+                return false;
+            }
+            if (other.graph != graph) {
+                return false;
+            }
+            if (other.locals.length != locals.length) {
+                return false;
+            }
+            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
+                            equals(other.monitorIds, monitorIds, monitorIds.length);
+        }
+        return false;
+    }
+
+    public void replace(ValueNode oldValue, ValueNode newValue) {
+        for (int i = 0; i < locals.length; i++) {
+            if (locals[i] == oldValue) {
+                locals[i] = newValue;
+            }
+        }
+        for (int i = 0; i < stackSize; i++) {
+            if (stack[i] == oldValue) {
+                stack[i] = newValue;
+            }
+        }
+    }
+
+    @Override
+    public boolean isAfterSideEffect() {
+        return sideEffects != null;
+    }
+
+    @Override
+    public Iterable<StateSplit> sideEffects() {
+        return sideEffects;
+    }
+
+    @Override
+    public void addSideEffect(StateSplit sideEffect) {
+        assert sideEffect != null;
+        assert sideEffect.hasSideEffect();
+        if (sideEffects == null) {
+            sideEffects = new ArrayList<>(4);
+        }
+        sideEffects.add(sideEffect);
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 15 11:55:52 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.java;
 
+import static com.oracle.graal.api.code.TypeCheckHints.*;
 import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
@@ -29,7 +30,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.type.StampFactory.*;
 import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.nodes.type.StampTool.*;
 import static java.lang.String.*;
@@ -63,6 +64,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -71,6 +73,125 @@
  */
 public class GraphBuilderPhase extends BasePhase<HighTierContext> {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
+        public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
+
+        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
+        public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert)
+        public static final StableOptionValue<Boolean> InlineIntrinsicsDuringParsing = new StableOptionValue<>(true);
+
+        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
+
+        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
+
+        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
+
+        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
+        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
+        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
+
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+
+        @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> HideSubstitutionStates = new OptionValue<>(false);
+
+        // @formatter:on
+    }
+
+    /**
+     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
+     * bytecode instructions as they are parsed.
+     */
+    public static final int TRACELEVEL_INSTRUCTIONS = 1;
+
+    /**
+     * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the
+     * frame state before each bytecode instruction as it is parsed.
+     */
+    public static final int TRACELEVEL_STATE = 2;
+
+    /**
+     * Meters the number of actual bytecodes parsed.
+     */
+    public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
+
+    /**
+     * Gets the kind of array elements for the array type code that appears in a
+     * {@link Bytecodes#NEWARRAY} bytecode.
+     *
+     * @param code the array type code
+     * @return the kind from the array type code
+     */
+    public static Class<?> arrayTypeCodeToClass(int code) {
+        // Checkstyle: stop
+        switch (code) {
+            case 4:
+                return boolean.class;
+            case 5:
+                return char.class;
+            case 6:
+                return float.class;
+            case 7:
+                return double.class;
+            case 8:
+                return byte.class;
+            case 9:
+                return short.class;
+            case 10:
+                return int.class;
+            case 11:
+                return long.class;
+            default:
+                throw new IllegalArgumentException("unknown array type code: " + code);
+        }
+        // Checkstyle: resume
+    }
+
+    protected static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
+
+    protected static boolean allPositive(double[] a) {
+        for (double d : a) {
+            if (d < 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Helper function that sums up the probabilities of all keys that lead to a specific successor.
+     *
+     * @return an array of size successorCount with the accumulated probability for each successor.
+     */
+    public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
+        double[] probability = new double[successorCount];
+        for (int i = 0; i < keySuccessors.length; i++) {
+            probability[keySuccessors[i]] += keyProbabilities[i];
+        }
+        return probability;
+    }
+
+    static class SuccessorInfo {
+
+        int blockIndex;
+        int actualIndex;
+
+        public SuccessorInfo(int blockSuccessorIndex) {
+            this.blockIndex = blockSuccessorIndex;
+            actualIndex = -1;
+        }
+    }
+
     private final GraphBuilderConfiguration graphBuilderConfig;
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
@@ -86,35 +207,38 @@
         return graphBuilderConfig;
     }
 
+    /**
+     * A scoped object for tasks to be performed after parsing an intrinsic such as processing
+     * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states.
+     */
     static class IntrinsicScope implements AutoCloseable {
         FrameState stateBefore;
         final Mark mark;
         final BytecodeParser parser;
 
-        static IntrinsicScope create(boolean enteringIntrinsic, BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) {
-            if (enteringIntrinsic) {
-                return new IntrinsicScope(parser, currentFrameState, args);
-            }
-            return null;
-        }
-
-        public IntrinsicScope(BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) {
+        /**
+         * Creates a scope for root parsing an intrinsic.
+         *
+         * @param parser the parsing context of the intrinsic
+         */
+        public IntrinsicScope(BytecodeParser parser) {
             this.parser = parser;
-            if (args == null) {
-                assert parser.parent == null;
-                assert parser.bci() == 0;
-                mark = null;
-            } else {
-                mark = parser.getGraph().getMark();
-                for (ValueNode arg : args) {
-                    currentFrameState.push(arg.getKind(), arg);
-                }
-                stateBefore = currentFrameState.create(parser.bci(), null);
-                for (int i = args.length - 1; i >= 0; i--) {
-                    ValueNode arg = args[i];
-                    currentFrameState.pop(arg.getKind());
-                }
-            }
+            assert parser.parent == null;
+            assert parser.bci() == 0;
+            mark = null;
+        }
+
+        /**
+         * Creates a scope for parsing an intrinsic during graph builder inlining.
+         *
+         * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic
+         * @param args the arguments to the call
+         */
+        public IntrinsicScope(BytecodeParser parser, ValueNode[] args) {
+            assert !parser.parsingIntrinsic();
+            this.parser = parser;
+            mark = parser.getGraph().getMark();
+            stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, args);
         }
 
         public void close() {
@@ -123,43 +247,56 @@
                 return;
             }
 
+            processPlaceholderFrameStates(intrinsic);
+        }
+
+        /**
+         * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states
+         * added to the graph while parsing/inlining the intrinsic for which this object exists.
+         */
+        private void processPlaceholderFrameStates(IntrinsicContext intrinsic) {
             FrameState stateAfterReturn = null;
             StructuredGraph graph = parser.getGraph();
             for (Node node : graph.getNewNodes(mark)) {
                 if (node instanceof FrameState) {
-                    FrameState fs = (FrameState) node;
-                    if (BytecodeFrame.isPlaceholderBci(fs.bci)) {
-                        if (fs.bci == BytecodeFrame.AFTER_BCI) {
-                            if (fs.stackSize() != 0) {
-                                assert fs.usages().count() == 1;
-                                ValueNode returnVal = fs.stackAt(0);
-                                assert returnVal == fs.usages().first();
-
-                                ValueNode tos = parser.frameState.pop(returnVal.getKind());
-                                parser.frameState.push(returnVal.getKind(), returnVal);
-                                FrameState newFs = parser.frameState.create(parser.stream.nextBCI(), null);
-                                fs.replaceAndDelete(newFs);
-                                parser.frameState.pop(returnVal.getKind());
-                                parser.frameState.push(tos.getKind(), tos);
+                    FrameState frameState = (FrameState) node;
+                    if (BytecodeFrame.isPlaceholderBci(frameState.bci)) {
+                        if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+                            FrameStateBuilder frameStateBuilder = parser.frameState;
+                            if (frameState.stackSize() != 0) {
+                                assert frameState.usages().count() == 1;
+                                ValueNode returnVal = frameState.stackAt(0);
+                                assert returnVal == frameState.usages().first();
+
+                                /*
+                                 * Swap the top-of-stack value with the side-effect return value
+                                 * using the frame state.
+                                 */
+                                ValueNode tos = frameStateBuilder.pop(returnVal.getKind());
+                                assert tos.getKind() == returnVal.getKind();
+                                FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, returnVal);
+                                frameState.replaceAndDelete(newFrameState);
+                                frameStateBuilder.push(tos.getKind(), tos);
                             } else {
                                 if (stateAfterReturn == null) {
-                                    if (intrinsic != null && intrinsic.isCompilationRoot()) {
+                                    if (intrinsic != null) {
+                                        assert intrinsic.isCompilationRoot();
                                         stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI));
                                     } else {
-                                        stateAfterReturn = parser.frameState.create(parser.stream.nextBCI(), null);
+                                        stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null);
                                     }
                                 }
-                                fs.replaceAndDelete(stateAfterReturn);
+                                frameState.replaceAndDelete(stateAfterReturn);
                             }
-                        } else if (fs.bci == BytecodeFrame.BEFORE_BCI) {
+                        } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
                             if (stateBefore == null) {
                                 stateBefore = graph.start().stateAfter();
                             }
-                            if (stateBefore != fs) {
-                                fs.replaceAndDelete(stateBefore);
+                            if (stateBefore != frameState) {
+                                frameState.replaceAndDelete(stateBefore);
                             }
                         } else {
-                            assert fs.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
+                            assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI;
                         }
                     }
                 }
@@ -203,11 +340,11 @@
             try {
                 IntrinsicContext intrinsicContext = initialIntrinsicContext;
                 BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, intrinsicContext);
-                HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph);
+                FrameStateBuilder frameState = new FrameStateBuilder(parser, method, graph);
 
                 frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
 
-                try (IntrinsicScope s = IntrinsicScope.create(intrinsicContext != null, parser, frameState, null)) {
+                try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(parser) : null) {
                     parser.build(graph.start(), frameState);
                 }
                 GraphUtil.normalizeLoops(graph);
@@ -279,9 +416,9 @@
         private static class Target {
 
             FixedNode fixed;
-            HIRFrameStateBuilder state;
-
-            public Target(FixedNode fixed, HIRFrameStateBuilder state) {
+            FrameStateBuilder state;
+
+            public Target(FixedNode fixed, FrameStateBuilder state) {
                 this.fixed = fixed;
                 this.state = state;
             }
@@ -305,7 +442,7 @@
             }
         }
 
-        public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext {
+        public class BytecodeParser implements GraphBuilderContext {
 
             private BciBlockMapping blockMap;
             private LocalLiveness liveness;
@@ -326,20 +463,28 @@
             private FixedWithNextNode lastInstr;                 // the last instruction added
             private final boolean explodeLoops;
             private final boolean mergeExplosions;
-            private final Map<HIRFrameStateBuilder, Integer> mergeExplosionsMap;
+            private final Map<FrameStateBuilder, Integer> mergeExplosionsMap;
             private Deque<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
             private boolean controlFlowSplit;
             private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this);
 
             private FixedWithNextNode[] firstInstructionArray;
-            private HIRFrameStateBuilder[] entryStateArray;
+            private FrameStateBuilder[] entryStateArray;
             private FixedWithNextNode[][] firstInstructionMatrix;
-            private HIRFrameStateBuilder[][] entryStateMatrix;
+            private FrameStateBuilder[][] entryStateMatrix;
 
             public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig,
                             OptimisticOptimizations optimisticOpts, int entryBCI, IntrinsicContext intrinsicContext) {
-                super(metaAccess, method, graphBuilderConfig, optimisticOpts, intrinsicContext);
+                this.graphBuilderConfig = graphBuilderConfig;
+                this.optimisticOpts = optimisticOpts;
+                this.metaAccess = metaAccess;
+                this.stream = new BytecodeStream(method.getCode());
+                this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
+                this.constantPool = method.getConstantPool();
+                this.method = method;
+                this.intrinsicContext = intrinsicContext;
+                assert metaAccess != null;
                 this.entryBCI = entryBCI;
                 this.parent = parent;
 
@@ -381,7 +526,7 @@
                 return this.beforeUnwindNode;
             }
 
-            protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
+            protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) {
                 if (PrintProfilingInformation.getValue() && profilingInfo != null) {
                     TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
                     TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
@@ -393,15 +538,13 @@
                     BciBlockMapping newMapping = BciBlockMapping.create(stream, method);
                     this.blockMap = newMapping;
                     this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()];
-                    this.entryStateArray = new HIRFrameStateBuilder[blockMap.getBlockCount()];
-
-                    if (graphBuilderConfig.doLivenessAnalysis()) {
-                        try (Scope s = Debug.scope("LivenessAnalysis")) {
-                            int maxLocals = method.getMaxLocals();
-                            liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
-                        } catch (Throwable e) {
-                            throw Debug.handle(e);
-                        }
+                    this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()];
+
+                    try (Scope s = Debug.scope("LivenessAnalysis")) {
+                        int maxLocals = method.getMaxLocals();
+                        liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
+                    } catch (Throwable e) {
+                        throw Debug.handle(e);
                     }
 
                     lastInstr = startInstruction;
@@ -704,7 +847,7 @@
                 return header.loopEnd + 1;
             }
 
-            private void addToMergeCache(HIRFrameStateBuilder key, int dimension) {
+            private void addToMergeCache(FrameStateBuilder key, int dimension) {
                 mergeExplosionsMap.put(key, dimension);
             }
 
@@ -743,7 +886,6 @@
             /**
              * @param type the unresolved type of the constant
              */
-            @Override
             protected void handleUnresolvedLoadConstant(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -753,7 +895,6 @@
              * @param type the unresolved type of the type check
              * @param object the object value whose type is being checked against {@code type}
              */
-            @Override
             protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new FixedGuardNode(graph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile));
@@ -764,7 +905,6 @@
              * @param type the unresolved type of the type check
              * @param object the object value whose type is being checked against {@code type}
              */
-            @Override
             protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
                 assert !graphBuilderConfig.eagerResolving();
                 AbstractBeginNode successor = graph.add(new BeginNode());
@@ -777,7 +917,6 @@
             /**
              * @param type the type being instantiated
              */
-            @Override
             protected void handleUnresolvedNewInstance(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -787,7 +926,6 @@
              * @param type the type of the array being instantiated
              * @param length the length of the array
              */
-            @Override
             protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -797,7 +935,6 @@
              * @param type the type being instantiated
              * @param dims the dimensions for the multi-array
              */
-            @Override
             protected void handleUnresolvedNewMultiArray(JavaType type, List<ValueNode> dims) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -808,7 +945,6 @@
              * @param receiver the object containing the field or {@code null} if {@code field} is
              *            static
              */
-            @Override
             protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -820,7 +956,6 @@
              * @param receiver the object containing the field or {@code null} if {@code field} is
              *            static
              */
-            @Override
             protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -829,7 +964,6 @@
             /**
              * @param type
              */
-            @Override
             protected void handleUnresolvedExceptionType(JavaType type) {
                 assert !graphBuilderConfig.eagerResolving();
                 append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
@@ -858,7 +992,7 @@
                     dispatchBlock = blockMap.getUnwindBlock();
                 }
 
-                HIRFrameStateBuilder dispatchState = frameState.copy();
+                FrameStateBuilder dispatchState = frameState.copy();
                 dispatchState.clearStack();
 
                 DispatchBeginNode dispatchBegin;
@@ -880,148 +1014,119 @@
                 return dispatchBegin;
             }
 
-            @Override
             protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, Kind kind) {
                 return LoadIndexedNode.create(array, index, kind, metaAccess, constantReflection);
             }
 
-            @Override
             protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) {
                 add(new StoreIndexedNode(array, index, kind, value));
             }
 
-            @Override
-            protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) {
                 return AddNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerSub(ValueNode x, ValueNode y) {
                 return SubNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerMul(ValueNode x, ValueNode y) {
                 return MulNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatAdd(ValueNode x, ValueNode y) {
                 return AddNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatSub(ValueNode x, ValueNode y) {
                 return SubNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatMul(ValueNode x, ValueNode y) {
                 return MulNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatDiv(ValueNode x, ValueNode y) {
                 return DivNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            protected ValueNode genFloatRem(ValueNode x, ValueNode y) {
                 return new RemNode(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) {
                 return new IntegerDivNode(x, y);
             }
 
-            @Override
-            protected ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genIntegerRem(ValueNode x, ValueNode y) {
                 return new IntegerRemNode(x, y);
             }
 
-            @Override
             protected ValueNode genNegateOp(ValueNode x) {
                 return (new NegateNode(x));
             }
 
-            @Override
-            protected ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genLeftShift(ValueNode x, ValueNode y) {
                 return new LeftShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genRightShift(ValueNode x, ValueNode y) {
                 return new RightShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) {
                 return new UnsignedRightShiftNode(x, y);
             }
 
-            @Override
-            protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genAnd(ValueNode x, ValueNode y) {
                 return AndNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genOr(ValueNode x, ValueNode y) {
                 return OrNode.create(x, y);
             }
 
-            @Override
-            protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) {
+            protected ValueNode genXor(ValueNode x, ValueNode y) {
                 return XorNode.create(x, y);
             }
 
-            @Override
             protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
                 return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
             }
 
-            @Override
             protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
                 return FloatConvertNode.create(op, input);
             }
 
-            @Override
             protected ValueNode genNarrow(ValueNode input, int bitCount) {
                 return NarrowNode.create(input, bitCount);
             }
 
-            @Override
             protected ValueNode genSignExtend(ValueNode input, int bitCount) {
                 return SignExtendNode.create(input, bitCount);
             }
 
-            @Override
             protected ValueNode genZeroExtend(ValueNode input, int bitCount) {
                 return ZeroExtendNode.create(input, bitCount);
             }
 
-            @Override
             protected void genGoto() {
                 appendGoto(currentBlock.getSuccessor(0));
                 assert currentBlock.numNormalSuccessors() == 1;
             }
 
-            @Override
             protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
                 return ObjectEqualsNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
                 return IntegerEqualsNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
                 return IntegerLessThanNode.create(x, y, constantReflection);
             }
 
-            @Override
             protected ValueNode genUnique(ValueNode x) {
                 return (ValueNode) graph.unique((Node & ValueNumberable) x);
             }
@@ -1030,49 +1135,40 @@
                 return new IfNode(condition, falseSuccessor, trueSuccessor, d);
             }
 
-            @Override
             protected void genThrow() {
                 ValueNode exception = frameState.apop();
                 append(new FixedGuardNode(graph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
                 lastInstr.setNext(handleException(exception, bci()));
             }
 
-            @Override
             protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) {
                 return CheckCastNode.create(type, object, profileForTypeCheck, forStoreCheck, graph.getAssumptions());
             }
 
-            @Override
             protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) {
                 return InstanceOfNode.create(type, object, profileForTypeCheck);
             }
 
-            @Override
             protected ValueNode genConditional(ValueNode x) {
                 return new ConditionalNode((LogicNode) x);
             }
 
-            @Override
             protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
                 return new NewInstanceNode(type, fillContents);
             }
 
-            @Override
             protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
                 return new NewArrayNode(elementType, length, fillContents);
             }
 
-            @Override
             protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, List<ValueNode> dimensions) {
                 return new NewMultiArrayNode(type, dimensions.toArray(new ValueNode[0]));
             }
 
-            @Override
             protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) {
                 return new LoadFieldNode(receiver, field);
             }
 
-            @Override
             protected ValueNode emitExplicitNullCheck(ValueNode receiver) {
                 if (StampTool.isPointerNonNull(receiver.stamp())) {
                     return receiver;
@@ -1089,7 +1185,6 @@
                 return nonNullReceiver;
             }
 
-            @Override
             protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
                 AbstractBeginNode trueSucc = graph.add(new BeginNode());
                 BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
@@ -1100,12 +1195,10 @@
                 exception.setNext(handleException(exception, bci()));
             }
 
-            @Override
             protected ValueNode genArrayLength(ValueNode x) {
                 return ArrayLengthNode.create(x, constantReflection);
             }
 
-            @Override
             protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
                 StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value);
                 append(storeFieldNode);
@@ -1128,7 +1221,6 @@
                 return false;
             }
 
-            @Override
             protected void genInvokeStatic(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target;
@@ -1144,7 +1236,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeInterface(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
@@ -1154,7 +1245,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeDynamic(JavaMethod target) {
                 if (target instanceof ResolvedJavaMethod) {
                     JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC);
@@ -1168,7 +1258,6 @@
                 }
             }
 
-            @Override
             protected void genInvokeVirtual(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     /*
@@ -1195,7 +1284,6 @@
 
             }
 
-            @Override
             protected void genInvokeSpecial(JavaMethod target) {
                 if (callTargetIsResolved(target)) {
                     assert target != null;
@@ -1209,6 +1297,16 @@
 
             private InvokeKind currentInvokeKind;
             private JavaType currentInvokeReturnType;
+            protected FrameStateBuilder frameState;
+            protected BciBlock currentBlock;
+            protected final BytecodeStream stream;
+            protected final GraphBuilderConfiguration graphBuilderConfig;
+            protected final ResolvedJavaMethod method;
+            protected final ProfilingInfo profilingInfo;
+            protected final OptimisticOptimizations optimisticOpts;
+            protected final ConstantPool constantPool;
+            protected final MetaAccessProvider metaAccess;
+            protected final IntrinsicContext intrinsicContext;
 
             public InvokeKind getInvokeKind() {
                 return currentInvokeKind;
@@ -1466,7 +1564,7 @@
              * @param format a format string
              * @param args arguments to the format string
              */
-            @Override
+
             protected void traceWithContext(String format, Object... args) {
                 StackTraceElement where = method.asStackTraceElement(bci());
                 TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
@@ -1487,10 +1585,10 @@
             }
 
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
-                try (IntrinsicScope s = IntrinsicScope.create(calleeIntrinsicContext != null && !parsingIntrinsic(), this, frameState, args)) {
+                try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, args) : null) {
 
                     BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
-                    HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph);
+                    FrameStateBuilder startFrameState = new FrameStateBuilder(parser, targetMethod, graph);
                     if (!targetMethod.isStatic()) {
                         args[0] = nullCheckedValue(args[0]);
                     }
@@ -1533,6 +1631,14 @@
             }
 
             protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, Kind resultType) {
+                if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
+                    /*
+                     * Clear non-live locals early so that the exception handler entry gets the
+                     * cleared state.
+                     */
+                    frameState.clearNonLiveLocals(currentBlock, liveness, false);
+                }
+
                 DispatchBeginNode exceptionEdge = handleException(null, bci());
                 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
                 frameState.pushReturn(resultType, invoke);
@@ -1540,7 +1646,6 @@
                 return invoke;
             }
 
-            @Override
             protected void genReturn(ValueNode returnVal, Kind returnKind) {
                 if (parsingIntrinsic() && returnVal != null) {
                     if (returnVal instanceof StateSplit) {
@@ -1603,7 +1708,6 @@
                 }
             }
 
-            @Override
             protected void genMonitorEnter(ValueNode x, int bci) {
                 MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth()));
                 MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId));
@@ -1611,7 +1715,6 @@
                 monitorEnter.setStateAfter(createFrameState(bci, monitorEnter));
             }
 
-            @Override
             protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) {
                 MonitorIdNode monitorId = frameState.peekMonitorId();
                 ValueNode lockedObject = frameState.popLock();
@@ -1622,7 +1725,6 @@
                 monitorExit.setStateAfter(createFrameState(bci, monitorExit));
             }
 
-            @Override
             protected void genJsr(int dest) {
                 BciBlock successor = currentBlock.getJsrSuccessor();
                 assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci();
@@ -1639,7 +1741,6 @@
                 appendGoto(successor);
             }
 
-            @Override
             protected void genRet(int localIndex) {
                 BciBlock successor = currentBlock.getRetSuccessor();
                 ValueNode local = frameState.loadLocal(localIndex);
@@ -1662,7 +1763,6 @@
                 return graph.unique(nextBciNode);
             }
 
-            @Override
             protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
                 if (value.isConstant()) {
                     JavaConstant constant = (JavaConstant) value.asConstant();
@@ -1684,7 +1784,6 @@
                 }
             }
 
-            @Override
             protected ConstantNode appendConstant(JavaConstant constant) {
                 assert constant != null;
                 return ConstantNode.forConstant(constant, metaAccess, graph);
@@ -1727,7 +1826,7 @@
                 }
             }
 
-            private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) {
+            private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) {
                 if (currentBlock != null && !explodeLoops) {
                     long exits = currentBlock.loops & ~targetBlock.loops;
                     if (exits != 0) {
@@ -1757,7 +1856,7 @@
                         if (targetBlock instanceof ExceptionDispatchBlock) {
                             bci = ((ExceptionDispatchBlock) targetBlock).deoptBci;
                         }
-                        HIRFrameStateBuilder newState = state.copy();
+                        FrameStateBuilder newState = state.copy();
                         for (BciBlock loop : exitLoops) {
                             LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop, this.getCurrentDimension());
                             LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin));
@@ -1780,7 +1879,7 @@
                 return new Target(target, state);
             }
 
-            private HIRFrameStateBuilder getEntryState(BciBlock block, int dimension) {
+            private FrameStateBuilder getEntryState(BciBlock block, int dimension) {
                 int id = block.id;
                 if (dimension == 0) {
                     return entryStateArray[id];
@@ -1789,9 +1888,9 @@
                 }
             }
 
-            private HIRFrameStateBuilder getEntryStateMultiDimension(int dimension, int id) {
+            private FrameStateBuilder getEntryStateMultiDimension(int dimension, int id) {
                 if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) {
-                    HIRFrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1];
+                    FrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1];
                     if (entryStateArrayEntry == null) {
                         return null;
                     }
@@ -1801,7 +1900,7 @@
                 }
             }
 
-            private void setEntryState(BciBlock block, int dimension, HIRFrameStateBuilder entryState) {
+            private void setEntryState(BciBlock block, int dimension, FrameStateBuilder entryState) {
                 int id = block.id;
                 if (dimension == 0) {
                     this.entryStateArray[id] = entryState;
@@ -1810,9 +1909,9 @@
                 }
             }
 
-            private void setEntryStateMultiDimension(int dimension, HIRFrameStateBuilder entryState, int id) {
+            private void setEntryStateMultiDimension(int dimension, FrameStateBuilder entryState, int id) {
                 if (entryStateMatrix == null) {
-                    entryStateMatrix = new HIRFrameStateBuilder[4][];
+                    entryStateMatrix = new FrameStateBuilder[4][];
                 }
                 if (dimension - 1 < entryStateMatrix.length) {
                     // We are within bounds.
@@ -1821,7 +1920,7 @@
                     entryStateMatrix = Arrays.copyOf(entryStateMatrix, Math.max(entryStateMatrix.length * 2, dimension));
                 }
                 if (entryStateMatrix[dimension - 1] == null) {
-                    entryStateMatrix[dimension - 1] = new HIRFrameStateBuilder[blockMap.getBlockCount()];
+                    entryStateMatrix[dimension - 1] = new FrameStateBuilder[blockMap.getBlockCount()];
                 }
                 entryStateMatrix[dimension - 1][id] = entryState;
             }
@@ -1872,7 +1971,7 @@
                 }
             }
 
-            private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
+            private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
                 assert probability >= 0 && probability <= 1.01 : probability;
                 if (isNeverExecutedCode(probability)) {
                     return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
@@ -1882,11 +1981,11 @@
                 }
             }
 
-            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
+            private FixedNode createTarget(BciBlock block, FrameStateBuilder state) {
                 return createTarget(block, state, false, false);
             }
 
-            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
+            private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
                 assert block != null && state != null;
                 assert !block.isExceptionEntry || state.stackSize() == 1;
 
@@ -1908,7 +2007,7 @@
                     targetNode = getFirstInstruction(block, operatingDimension);
                     Target target = checkLoopExit(targetNode, block, state);
                     FixedNode result = target.fixed;
-                    HIRFrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
+                    FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
                     setEntryState(block, operatingDimension, currentEntryState);
                     currentEntryState.clearNonLiveLocals(block, liveness, true);
 
@@ -1981,14 +2080,14 @@
                 return result;
             }
 
-            private int findOperatingDimension(BciBlock block, HIRFrameStateBuilder state) {
+            private int findOperatingDimension(BciBlock block, FrameStateBuilder state) {
                 if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) {
                     return findOperatingDimensionWithLoopExplosion(block, state);
                 }
                 return this.getCurrentDimension();
             }
 
-            private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) {
+            private int findOperatingDimensionWithLoopExplosion(BciBlock block, FrameStateBuilder state) {
                 for (ExplodedLoopContext context : explodeLoopsContext) {
                     if (context.header == block) {
 
@@ -2039,7 +2138,7 @@
              * Returns a block begin node with the specified state. If the specified probability is
              * 0, the block deoptimizes immediately.
              */
-            private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
+            private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) {
                 FixedNode target = createTarget(probability, block, stateAfter);
                 AbstractBeginNode begin = BeginNode.begin(target);
 
@@ -2048,7 +2147,7 @@
                 return begin;
             }
 
-            private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) {
+            private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) {
                 if (target.isStatic()) {
                     return appendConstant(target.getDeclaringClass().getJavaClass());
                 } else {
@@ -2187,7 +2286,6 @@
                 }
             }
 
-            @Override
             protected void iterateBytecodesForBlock(BciBlock block) {
                 if (block.isLoopHeader && !explodeLoops) {
                     // Create the loop header block, which later will merge the backward branches of
@@ -2197,7 +2295,7 @@
                     lastInstr = loopBegin;
 
                     // Create phi functions for all local variables and operand stack slots.
-                    frameState.insertLoopPhis(liveness, block.loopId, loopBegin);
+                    frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis());
                     loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
 
                     /*
@@ -2282,6 +2380,11 @@
                 }
             }
 
+            /* Also a hook for subclasses. */
+            protected boolean forceLoopPhis() {
+                return graph.isOSR();
+            }
+
             protected boolean checkLastInstruction() {
                 if (lastInstr instanceof BeginNode) {
                     // ignore
@@ -2310,7 +2413,7 @@
              * @param state The current frame state.
              * @return Returns the (new) last instruction.
              */
-            protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) {
+            protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) {
                 return instr;
             }
 
@@ -2350,7 +2453,6 @@
                 }
             }
 
-            @Override
             protected void genIf(ValueNode x, Condition cond, ValueNode y) {
                 assert currentBlock.getSuccessorCount() == 2;
                 BciBlock trueBlock = currentBlock.getSuccessor(0);
@@ -2600,6 +2702,910 @@
             private BytecodePosition createBytecodePosition() {
                 return frameState.createBytecodePosition(bci());
             }
+
+            public void setCurrentFrameState(FrameStateBuilder frameState) {
+                this.frameState = frameState;
+            }
+
+            protected final BytecodeStream getStream() {
+                return stream;
+            }
+
+            public int bci() {
+                return stream.currentBCI();
+            }
+
+            public void loadLocal(int index, Kind kind) {
+                frameState.push(kind, frameState.loadLocal(index));
+            }
+
+            public void storeLocal(Kind kind, int index) {
+                ValueNode value;
+                if (kind == Kind.Object) {
+                    value = frameState.xpop();
+                    // astore and astore_<n> may be used to store a returnAddress (jsr)
+                    assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
+                } else {
+                    value = frameState.pop(kind);
+                }
+                frameState.storeLocal(index, value, kind);
+            }
+
+            private void genLoadConstant(int cpi, int opcode) {
+                Object con = lookupConstant(cpi, opcode);
+
+                if (con instanceof JavaType) {
+                    // this is a load of class constant which might be unresolved
+                    JavaType type = (JavaType) con;
+                    if (type instanceof ResolvedJavaType) {
+                        frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass()));
+                    } else {
+                        handleUnresolvedLoadConstant(type);
+                    }
+                } else if (con instanceof JavaConstant) {
+                    JavaConstant constant = (JavaConstant) con;
+                    frameState.push(constant.getKind().getStackKind(), appendConstant(constant));
+                } else {
+                    throw new Error("lookupConstant returned an object of incorrect type");
+                }
+            }
+
+            private void genLoadIndexed(Kind kind) {
+                ValueNode index = frameState.ipop();
+                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                if (!tryLoadIndexedPlugin(kind, index, array)) {
+                    frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
+                }
+            }
+
+            protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) {
+                LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin();
+                if (loadIndexedPlugin != null && loadIndexedPlugin.apply(this, array, index, kind)) {
+                    if (TraceParserPlugins.getValue()) {
+                        traceWithContext("used load indexed plugin");
+                    }
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+
+            private void genStoreIndexed(Kind kind) {
+                ValueNode value = frameState.pop(kind.getStackKind());
+                ValueNode index = frameState.ipop();
+                ValueNode array = emitExplicitExceptions(frameState.apop(), index);
+                genStoreIndexed(array, index, kind, value);
+            }
+
+            private void stackOp(int opcode) {
+                switch (opcode) {
+                    case DUP_X1: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP_X2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2_X1: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case DUP2_X2: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        ValueNode w3 = frameState.xpop();
+                        ValueNode w4 = frameState.xpop();
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        frameState.xpush(w4);
+                        frameState.xpush(w3);
+                        frameState.xpush(w2);
+                        frameState.xpush(w1);
+                        break;
+                    }
+                    case SWAP: {
+                        ValueNode w1 = frameState.xpop();
+                        ValueNode w2 = frameState.xpop();
+                        frameState.xpush(w1);
+                        frameState.xpush(w2);
+                        break;
+                    }
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            private void genArithmeticOp(Kind result, int opcode) {
+                ValueNode y = frameState.pop(result);
+                ValueNode x = frameState.pop(result);
+                ValueNode v;
+                switch (opcode) {
+                    case IADD:
+                    case LADD:
+                        v = genIntegerAdd(x, y);
+                        break;
+                    case FADD:
+                    case DADD:
+                        v = genFloatAdd(x, y);
+                        break;
+                    case ISUB:
+                    case LSUB:
+                        v = genIntegerSub(x, y);
+                        break;
+                    case FSUB:
+                    case DSUB:
+                        v = genFloatSub(x, y);
+                        break;
+                    case IMUL:
+                    case LMUL:
+                        v = genIntegerMul(x, y);
+                        break;
+                    case FMUL:
+                    case DMUL:
+                        v = genFloatMul(x, y);
+                        break;
+                    case FDIV:
+                    case DDIV:
+                        v = genFloatDiv(x, y);
+                        break;
+                    case FREM:
+                    case DREM:
+                        v = genFloatRem(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(result, append(v));
+            }
+
+            private void genIntegerDivOp(Kind result, int opcode) {
+                ValueNode y = frameState.pop(result);
+                ValueNode x = frameState.pop(result);
+                ValueNode v;
+                switch (opcode) {
+                    case IDIV:
+                    case LDIV:
+                        v = genIntegerDiv(x, y);
+                        break;
+                    case IREM:
+                    case LREM:
+                        v = genIntegerRem(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(result, append(v));
+            }
+
+            private void genNegateOp(Kind kind) {
+                frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
+            }
+
+            private void genShiftOp(Kind kind, int opcode) {
+                ValueNode s = frameState.ipop();
+                ValueNode x = frameState.pop(kind);
+                ValueNode v;
+                switch (opcode) {
+                    case ISHL:
+                    case LSHL:
+                        v = genLeftShift(x, s);
+                        break;
+                    case ISHR:
+                    case LSHR:
+                        v = genRightShift(x, s);
+                        break;
+                    case IUSHR:
+                    case LUSHR:
+                        v = genUnsignedRightShift(x, s);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(kind, append(v));
+            }
+
+            private void genLogicOp(Kind kind, int opcode) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                ValueNode v;
+                switch (opcode) {
+                    case IAND:
+                    case LAND:
+                        v = genAnd(x, y);
+                        break;
+                    case IOR:
+                    case LOR:
+                        v = genOr(x, y);
+                        break;
+                    case IXOR:
+                    case LXOR:
+                        v = genXor(x, y);
+                        break;
+                    default:
+                        throw new GraalInternalError("should not reach");
+                }
+                frameState.push(kind, append(v));
+            }
+
+            private void genCompareOp(Kind kind, boolean isUnorderedLess) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
+            }
+
+            private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
+            }
+
+            private void genSignExtend(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                if (from != from.getStackKind()) {
+                    input = append(genNarrow(input, from.getBitCount()));
+                }
+                frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount())));
+            }
+
+            private void genZeroExtend(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                if (from != from.getStackKind()) {
+                    input = append(genNarrow(input, from.getBitCount()));
+                }
+                frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount())));
+            }
+
+            private void genNarrow(Kind from, Kind to) {
+                ValueNode input = frameState.pop(from.getStackKind());
+                frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
+            }
+
+            private void genIncrement() {
+                int index = getStream().readLocalIndex();
+                int delta = getStream().readIncrement();
+                ValueNode x = frameState.loadLocal(index);
+                ValueNode y = appendConstant(JavaConstant.forInt(delta));
+                frameState.storeLocal(index, append(genIntegerAdd(x, y)));
+            }
+
+            private void genIfZero(Condition cond) {
+                ValueNode y = appendConstant(JavaConstant.INT_0);
+                ValueNode x = frameState.ipop();
+                genIf(x, cond, y);
+            }
+
+            private void genIfNull(Condition cond) {
+                ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
+                ValueNode x = frameState.apop();
+                genIf(x, cond, y);
+            }
+
+            private void genIfSame(Kind kind, Condition cond) {
+                ValueNode y = frameState.pop(kind);
+                ValueNode x = frameState.pop(kind);
+                genIf(x, cond, y);
+            }
+
+            protected JavaType lookupType(int cpi, int bytecode) {
+                maybeEagerlyResolve(cpi, bytecode);
+                JavaType result = constantPool.lookupType(cpi, bytecode);
+                assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType;
+                return result;
+            }
+
+            private JavaMethod lookupMethod(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                JavaMethod result = constantPool.lookupMethod(cpi, opcode);
+                /*
+                 * In general, one cannot assume that the declaring class being initialized is
+                 * useful, since the actual concrete receiver may be a different class (except for
+                 * static calls). Also, interfaces are initialized only under special circumstances,
+                 * so that this assertion would often fail for interface calls.
+                 */
+                assert !graphBuilderConfig.unresolvedIsError() ||
+                                (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
+                return result;
+            }
+
+            private JavaField lookupField(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                JavaField result = constantPool.lookupField(cpi, opcode);
+                assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
+                return result;
+            }
+
+            private Object lookupConstant(int cpi, int opcode) {
+                maybeEagerlyResolve(cpi, opcode);
+                Object result = constantPool.lookupConstant(cpi);
+                assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result;
+                return result;
+            }
+
+            private void maybeEagerlyResolve(int cpi, int bytecode) {
+                if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) {
+                    constantPool.loadReferencedType(cpi, bytecode);
+                }
+            }
+
+            private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
+                if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
+                    return null;
+                } else {
+                    return profilingInfo.getTypeProfile(bci());
+                }
+            }
+
+            private void genCheckCast() {
+                int cpi = getStream().readCPI();
+                JavaType type = lookupType(cpi, CHECKCAST);
+                ValueNode object = frameState.apop();
+                if (type instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+                    JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
+                    TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
+                    if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) {
+                        ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
+                        frameState.apush(checkCastNode);
+                    }
+                } else {
+                    handleUnresolvedCheckCast(type, object);
+                }
+            }
+
+            private void genInstanceOf() {
+                int cpi = getStream().readCPI();
+                JavaType type = lookupType(cpi, INSTANCEOF);
+                ValueNode object = frameState.apop();
+                if (type instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+                    JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
+                    TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
+                    if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) {
+                        ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile);
+                        frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
+                    }
+                } else {
+                    handleUnresolvedInstanceOf(type, object);
+                }
+            }
+
+            void genNewInstance(int cpi) {
+                JavaType type = lookupType(cpi, NEW);
+                if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
+                    ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
+                    if (skippedExceptionTypes != null) {
+                        for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
+                            if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
+                                append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
+                                return;
+                            }
+                        }
+                    }
+                    frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
+                } else {
+                    handleUnresolvedNewInstance(type);
+                }
+            }
+
+            private void genNewPrimitiveArray(int typeCode) {
+                Class<?> clazz = arrayTypeCodeToClass(typeCode);
+                ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz);
+                frameState.apush(append(createNewArray(elementType, frameState.ipop(), true)));
+            }
+
+            private void genNewObjectArray(int cpi) {
+                JavaType type = lookupType(cpi, ANEWARRAY);
+                ValueNode length = frameState.ipop();
+                if (type instanceof ResolvedJavaType) {
+                    frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
+                } else {
+                    handleUnresolvedNewObjectArray(type, length);
+                }
+
+            }
+
+            private void genNewMultiArray(int cpi) {
+                JavaType type = lookupType(cpi, MULTIANEWARRAY);
+                int rank = getStream().readUByte(bci() + 3);
+                List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
+                for (int i = rank - 1; i >= 0; i--) {
+                    dims.set(i, frameState.ipop());
+                }
+                if (type instanceof ResolvedJavaType) {
+                    frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims)));
+                } else {
+                    handleUnresolvedNewMultiArray(type, dims);
+                }
+            }
+
+            private void genGetField(JavaField field) {
+                Kind kind = field.getKind();
+                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+                    LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
+                    if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
+                        appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
+                    }
+                } else {
+                    handleUnresolvedLoadField(field, receiver);
+                }
+            }
+
+            /**
+             * @param receiver the receiver of an object based operation
+             * @param index the index of an array based operation that is to be tested for out of
+             *            bounds. This is null for a non-array operation.
+             * @return the receiver value possibly modified to have a tighter stamp
+             */
+            protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
+                assert receiver != null;
+                if (graphBuilderConfig.omitAllExceptionEdges() ||
+                                profilingInfo == null ||
+                                (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
+                    return receiver;
+                }
+
+                ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
+                if (index != null) {
+                    ValueNode length = append(genArrayLength(nonNullReceiver));
+                    emitExplicitBoundsCheck(index, length);
+                }
+                EXPLICIT_EXCEPTIONS.increment();
+                return nonNullReceiver;
+            }
+
+            private void genPutField(JavaField field) {
+                ValueNode value = frameState.pop(field.getKind().getStackKind());
+                ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
+                    genStoreField(receiver, (ResolvedJavaField) field, value);
+                } else {
+                    handleUnresolvedStoreField(field, value, receiver);
+                }
+            }
+
+            private void genGetStatic(JavaField field) {
+                Kind kind = field.getKind();
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+                    ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+                    // Javac does not allow use of "$assertionsDisabled" for a field name but
+                    // Eclipse does in which case a suffix is added to the generated field.
+                    if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) {
+                        appendOptimizedLoadField(kind, ConstantNode.forBoolean(true));
+                        return;
+                    }
+
+                    LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
+                    if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) {
+                        appendOptimizedLoadField(kind, genLoadField(null, resolvedField));
+                    }
+                } else {
+                    handleUnresolvedLoadField(field, null);
+                }
+            }
+
+            public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) {
+                return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field);
+            }
+
+            private void genPutStatic(JavaField field) {
+                ValueNode value = frameState.pop(field.getKind().getStackKind());
+                if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
+                    genStoreField(null, (ResolvedJavaField) field, value);
+                } else {
+                    handleUnresolvedStoreField(field, value, null);
+                }
+            }
+
+            protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
+                // append the load to the instruction
+                ValueNode optimized = append(load);
+                frameState.push(kind.getStackKind(), optimized);
+            }
+
+            private double[] switchProbability(int numberOfCases, int bci) {
+                double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
+                if (prob != null) {
+                    assert prob.length == numberOfCases;
+                } else {
+                    Debug.log("Missing probability (switch) in %s at bci %d", method, bci);
+                    prob = new double[numberOfCases];
+                    for (int i = 0; i < numberOfCases; i++) {
+                        prob[i] = 1.0d / numberOfCases;
+                    }
+                }
+                assert allPositive(prob);
+                return prob;
+            }
+
+            private void genSwitch(BytecodeSwitch bs) {
+                int bci = bci();
+                ValueNode value = frameState.ipop();
+
+                int nofCases = bs.numberOfCases();
+                double[] keyProbabilities = switchProbability(nofCases + 1, bci);
+
+                Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
+                for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
+                    assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
+                    if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
+                        bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
+                    }
+                }
+
+                ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
+                int[] keys = new int[nofCases];
+                int[] keySuccessors = new int[nofCases + 1];
+                int deoptSuccessorIndex = -1;
+                int nextSuccessorIndex = 0;
+                boolean constantValue = value.isConstant();
+                for (int i = 0; i < nofCases + 1; i++) {
+                    if (i < nofCases) {
+                        keys[i] = bs.keyAt(i);
+                    }
+
+                    if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
+                        if (deoptSuccessorIndex < 0) {
+                            deoptSuccessorIndex = nextSuccessorIndex++;
+                            actualSuccessors.add(null);
+                        }
+                        keySuccessors[i] = deoptSuccessorIndex;
+                    } else {
+                        int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i);
+                        SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
+                        if (info.actualIndex < 0) {
+                            info.actualIndex = nextSuccessorIndex++;
+                            actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
+                        }
+                        keySuccessors[i] = info.actualIndex;
+                    }
+                }
+
+                genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors);
+
+            }
+
+            protected boolean isNeverExecutedCode(double probability) {
+                return probability == 0 && optimisticOpts.removeNeverExecutedCode();
+            }
+
+            protected double branchProbability() {
+                if (profilingInfo == null) {
+                    return 0.5;
+                }
+                assert assertAtIfBytecode();
+                double probability = profilingInfo.getBranchTakenProbability(bci());
+                if (probability < 0) {
+                    assert probability == -1 : "invalid probability";
+                    Debug.log("missing probability in %s at bci %d", method, bci());
+                    probability = 0.5;
+                }
+
+                if (!optimisticOpts.removeNeverExecutedCode()) {
+                    if (probability == 0) {
+                        probability = 0.0000001;
+                    } else if (probability == 1) {
+                        probability = 0.999999;
+                    }
+                }
+                return probability;
+            }
+
+            private boolean assertAtIfBytecode() {
+                int bytecode = stream.currentBC();
+                switch (bytecode) {
+                    case IFEQ:
+                    case IFNE:
+                    case IFLT:
+                    case IFGE:
+                    case IFGT:
+                    case IFLE:
+                    case IF_ICMPEQ:
+                    case IF_ICMPNE:
+                    case IF_ICMPLT:
+                    case IF_ICMPGE:
+                    case IF_ICMPGT:
+                    case IF_ICMPLE:
+                    case IF_ACMPEQ:
+                    case IF_ACMPNE:
+                    case IFNULL:
+                    case IFNONNULL:
+                        return true;
+                }
+                assert false : String.format("%x is not an if bytecode", bytecode);
+                return true;
+            }
+
+            public final void processBytecode(int bci, int opcode) {
+                int cpi;
+
+                // Checkstyle: stop
+                // @formatter:off
+                switch (opcode) {
+                    case NOP            : /* nothing to do */ break;
+                    case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
+                    case ICONST_M1      : // fall through
+                    case ICONST_0       : // fall through
+                    case ICONST_1       : // fall through
+                    case ICONST_2       : // fall through
+                    case ICONST_3       : // fall through
+                    case ICONST_4       : // fall through
+                    case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
+                    case LCONST_0       : // fall through
+                    case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
+                    case FCONST_0       : // fall through
+                    case FCONST_1       : // fall through
+                    case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
+                    case DCONST_0       : // fall through
+                    case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
+                    case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
+                    case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
+                    case LDC            : // fall through
+                    case LDC_W          : // fall through
+                    case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
+                    case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
+                    case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
+                    case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
+                    case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
+                    case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
+                    case ILOAD_0        : // fall through
+                    case ILOAD_1        : // fall through
+                    case ILOAD_2        : // fall through
+                    case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
+                    case LLOAD_0        : // fall through
+                    case LLOAD_1        : // fall through
+                    case LLOAD_2        : // fall through
+                    case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
+                    case FLOAD_0        : // fall through
+                    case FLOAD_1        : // fall through
+                    case FLOAD_2        : // fall through
+                    case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
+                    case DLOAD_0        : // fall through
+                    case DLOAD_1        : // fall through
+                    case DLOAD_2        : // fall through
+                    case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
+                    case ALOAD_0        : // fall through
+                    case ALOAD_1        : // fall through
+                    case ALOAD_2        : // fall through
+                    case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
+                    case IALOAD         : genLoadIndexed(Kind.Int   ); break;
+                    case LALOAD         : genLoadIndexed(Kind.Long  ); break;
+                    case FALOAD         : genLoadIndexed(Kind.Float ); break;
+                    case DALOAD         : genLoadIndexed(Kind.Double); break;
+                    case AALOAD         : genLoadIndexed(Kind.Object); break;
+                    case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
+                    case CALOAD         : genLoadIndexed(Kind.Char  ); break;
+                    case SALOAD         : genLoadIndexed(Kind.Short ); break;
+                    case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
+                    case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
+                    case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
+                    case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
+                    case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
+                    case ISTORE_0       : // fall through
+                    case ISTORE_1       : // fall through
+                    case ISTORE_2       : // fall through
+                    case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
+                    case LSTORE_0       : // fall through
+                    case LSTORE_1       : // fall through
+                    case LSTORE_2       : // fall through
+                    case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
+                    case FSTORE_0       : // fall through
+                    case FSTORE_1       : // fall through
+                    case FSTORE_2       : // fall through
+                    case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
+                    case DSTORE_0       : // fall through
+                    case DSTORE_1       : // fall through
+                    case DSTORE_2       : // fall through
+                    case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
+                    case ASTORE_0       : // fall through
+                    case ASTORE_1       : // fall through
+                    case ASTORE_2       : // fall through
+                    case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
+                    case IASTORE        : genStoreIndexed(Kind.Int   ); break;
+                    case LASTORE        : genStoreIndexed(Kind.Long  ); break;
+                    case FASTORE        : genStoreIndexed(Kind.Float ); break;
+                    case DASTORE        : genStoreIndexed(Kind.Double); break;
+                    case AASTORE        : genStoreIndexed(Kind.Object); break;
+                    case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
+                    case CASTORE        : genStoreIndexed(Kind.Char  ); break;
+                    case SASTORE        : genStoreIndexed(Kind.Short ); break;
+                    case POP            : frameState.xpop(); break;
+                    case POP2           : frameState.xpop(); frameState.xpop(); break;
+                    case DUP            : frameState.xpush(frameState.xpeek()); break;
+                    case DUP_X1         : // fall through
+                    case DUP_X2         : // fall through
+                    case DUP2           : // fall through
+                    case DUP2_X1        : // fall through
+                    case DUP2_X2        : // fall through
+                    case SWAP           : stackOp(opcode); break;
+                    case IADD           : // fall through
+                    case ISUB           : // fall through
+                    case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
+                    case IDIV           : // fall through
+                    case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
+                    case LADD           : // fall through
+                    case LSUB           : // fall through
+                    case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
+                    case LDIV           : // fall through
+                    case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
+                    case FADD           : // fall through
+                    case FSUB           : // fall through
+                    case FMUL           : // fall through
+                    case FDIV           : // fall through
+                    case FREM           : genArithmeticOp(Kind.Float, opcode); break;
+                    case DADD           : // fall through
+                    case DSUB           : // fall through
+                    case DMUL           : // fall through
+                    case DDIV           : // fall through
+                    case DREM           : genArithmeticOp(Kind.Double, opcode); break;
+                    case INEG           : genNegateOp(Kind.Int); break;
+                    case LNEG           : genNegateOp(Kind.Long); break;
+                    case FNEG           : genNegateOp(Kind.Float); break;
+                    case DNEG           : genNegateOp(Kind.Double); break;
+                    case ISHL           : // fall through
+                    case ISHR           : // fall through
+                    case IUSHR          : genShiftOp(Kind.Int, opcode); break;
+                    case IAND           : // fall through
+                    case IOR            : // fall through
+                    case IXOR           : genLogicOp(Kind.Int, opcode); break;
+                    case LSHL           : // fall through
+                    case LSHR           : // fall through
+                    case LUSHR          : genShiftOp(Kind.Long, opcode); break;
+                    case LAND           : // fall through
+                    case LOR            : // fall through
+                    case LXOR           : genLogicOp(Kind.Long, opcode); break;
+                    case IINC           : genIncrement(); break;
+                    case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
+                    case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
+                    case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
+                    case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
+                    case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
+                    case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
+                    case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
+                    case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
+                    case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
+                    case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
+                    case L2I            : genNarrow(Kind.Long, Kind.Int); break;
+                    case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
+                    case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
+                    case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
+                    case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
+                    case LCMP           : genCompareOp(Kind.Long, false); break;
+                    case FCMPL          : genCompareOp(Kind.Float, true); break;
+                    case FCMPG          : genCompareOp(Kind.Float, false); break;
+                    case DCMPL          : genCompareOp(Kind.Double, true); break;
+                    case DCMPG          : genCompareOp(Kind.Double, false); break;
+                    case IFEQ           : genIfZero(Condition.EQ); break;
+                    case IFNE           : genIfZero(Condition.NE); break;
+                    case IFLT           : genIfZero(Condition.LT); break;
+                    case IFGE           : genIfZero(Condition.GE); break;
+                    case IFGT           : genIfZero(Condition.GT); break;
+                    case IFLE           : genIfZero(Condition.LE); break;
+                    case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
+                    case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
+                    case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
+                    case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
+                    case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
+                    case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
+                    case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
+                    case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
+                    case GOTO           : genGoto(); break;
+                    case JSR            : genJsr(stream.readBranchDest()); break;
+                    case RET            : genRet(stream.readLocalIndex()); break;
+                    case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
+                    case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
+                    case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
+                    case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
+                    case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
+                    case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
+                    case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
+                    case RETURN         : genReturn(null, Kind.Void); break;
+                    case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
+                    case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
+                    case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
+                    case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
+                    case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
+                    case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
+                    case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
+                    case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
+                    case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+                    case NEW            : genNewInstance(stream.readCPI()); break;
+                    case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
+                    case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
+                    case ARRAYLENGTH    : genArrayLength(); break;
+                    case ATHROW         : genThrow(); break;
+                    case CHECKCAST      : genCheckCast(); break;
+                    case INSTANCEOF     : genInstanceOf(); break;
+                    case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
+                    case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
+                    case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
+                    case IFNULL         : genIfNull(Condition.EQ); break;
+                    case IFNONNULL      : genIfNull(Condition.NE); break;
+                    case GOTO_W         : genGoto(); break;
+                    case JSR_W          : genJsr(stream.readBranchDest()); break;
+                    case BREAKPOINT:
+                        throw new BailoutException("concurrent setting of breakpoint");
+                    default:
+                        throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
+                }
+                // @formatter:on
+                // Checkstyle: resume
+            }
+
+            private void genArrayLength() {
+                frameState.ipush(append(genArrayLength(frameState.apop())));
+            }
+
+            public ResolvedJavaMethod getMethod() {
+                return method;
+            }
+
+            public FrameStateBuilder getFrameStateBuilder() {
+                return frameState;
+            }
+
+            protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
+                if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
+                    traceInstructionHelper(bci, opcode, blockStart);
+                }
+                return true;
+            }
+
+            private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
+                StringBuilder sb = new StringBuilder(40);
+                sb.append(blockStart ? '+' : '|');
+                if (bci < 10) {
+                    sb.append("  ");
+                } else if (bci < 100) {
+                    sb.append(' ');
+                }
+                sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode));
+                for (int i = bci + 1; i < stream.nextBCI(); ++i) {
+                    sb.append(' ').append(stream.readUByte(i));
+                }
+                if (!currentBlock.getJsrScope().isEmpty()) {
+                    sb.append(' ').append(currentBlock.getJsrScope());
+                }
+                Debug.log("%s", sb);
+            }
+
+            public boolean parsingIntrinsic() {
+                return intrinsicContext != null;
+            }
+
+            public BytecodeParser getNonIntrinsicAncestor() {
+                BytecodeParser ancestor = parent;
+                while (ancestor != null && ancestor.parsingIntrinsic()) {
+                    ancestor = ancestor.parent;
+                }
+                return ancestor;
+            }
         }
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1020 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.java;
-
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.IntrinsicContext.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
-
-public final class HIRFrameStateBuilder implements SideEffectsState {
-
-    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
-    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
-
-    protected final BytecodeParser parser;
-    protected final ResolvedJavaMethod method;
-    protected int stackSize;
-    protected final ValueNode[] locals;
-    protected final ValueNode[] stack;
-    protected ValueNode[] lockedObjects;
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    protected boolean rethrowException;
-
-    private MonitorIdNode[] monitorIds;
-    private final StructuredGraph graph;
-    private FrameState outerFrameState;
-
-    /**
-     * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
-     * than one when the current block contains no side-effects but merging predecessor blocks do.
-     */
-    protected List<StateSplit> sideEffects;
-
-    /**
-     * Creates a new frame state builder for the given method and the given target graph.
-     *
-     * @param method the method whose frame is simulated
-     * @param graph the target graph of Graal nodes created by the builder
-     */
-    public HIRFrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) {
-        this.parser = parser;
-        this.method = method;
-        this.locals = allocateArray(method.getMaxLocals());
-        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
-        this.lockedObjects = allocateArray(0);
-
-        assert graph != null;
-
-        this.monitorIds = EMPTY_MONITOR_ARRAY;
-        this.graph = graph;
-    }
-
-    public void initializeFromArgumentsArray(ValueNode[] arguments) {
-
-        int javaIndex = 0;
-        int index = 0;
-        if (!method.isStatic()) {
-            // set the receiver
-            locals[javaIndex] = arguments[index];
-            javaIndex = 1;
-            index = 1;
-        }
-        Signature sig = method.getSignature();
-        int max = sig.getParameterCount(false);
-        for (int i = 0; i < max; i++) {
-            Kind kind = sig.getParameterKind(i);
-            locals[javaIndex] = arguments[index];
-            javaIndex += kind.getSlotCount();
-            index++;
-        }
-    }
-
-    public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
-
-        int javaIndex = 0;
-        int index = 0;
-        if (!method.isStatic()) {
-            // add the receiver
-            FloatingNode receiver = null;
-            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
-            if (parameterPlugin != null) {
-                receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp);
-            }
-            if (receiver == null) {
-                receiver = new ParameterNode(javaIndex, receiverStamp);
-            }
-            locals[javaIndex] = graph.unique(receiver);
-            javaIndex = 1;
-            index = 1;
-        }
-        Signature sig = method.getSignature();
-        int max = sig.getParameterCount(false);
-        ResolvedJavaType accessingClass = method.getDeclaringClass();
-        for (int i = 0; i < max; i++) {
-            JavaType type = sig.getParameterType(i, accessingClass);
-            if (eagerResolve) {
-                type = type.resolve(accessingClass);
-            }
-            Kind kind = type.getKind();
-            Stamp stamp;
-            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
-                stamp = StampFactory.declared((ResolvedJavaType) type);
-            } else {
-                stamp = StampFactory.forKind(kind);
-            }
-            FloatingNode param = null;
-            if (parameterPlugin != null) {
-                param = parameterPlugin.interceptParameter(parser, index, stamp);
-            }
-            if (param == null) {
-                param = new ParameterNode(index, stamp);
-            }
-            locals[javaIndex] = graph.unique(param);
-            javaIndex += kind.getSlotCount();
-            index++;
-        }
-    }
-
-    private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
-        this.parser = other.parser;
-        this.method = other.method;
-        this.stackSize = other.stackSize;
-        this.locals = other.locals.clone();
-        this.stack = other.stack.clone();
-        this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
-        this.rethrowException = other.rethrowException;
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-
-        assert other.graph != null;
-        graph = other.graph;
-        monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
-
-        assert locals.length == method.getMaxLocals();
-        assert stack.length == Math.max(1, method.getMaxStackSize());
-        assert lockedObjects.length == monitorIds.length;
-    }
-
-    private static ValueNode[] allocateArray(int length) {
-        return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[locals: [");
-        for (int i = 0; i < locals.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id));
-        }
-        sb.append("] stack: [");
-        for (int i = 0; i < stackSize; i++) {
-            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id));
-        }
-        sb.append("] locks: [");
-        for (int i = 0; i < lockedObjects.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id));
-        }
-        sb.append("]");
-        if (rethrowException) {
-            sb.append(" rethrowException");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    public FrameState create(int bci, StateSplit forStateSplit) {
-        if (parser.parsingIntrinsic()) {
-            return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit);
-        }
-
-        // Skip intrinsic frames
-        BytecodeParser parent = (BytecodeParser) parser.getNonReplacementAncestor();
-        return create(bci, parent, false);
-    }
-
-    public FrameState create(int bci, BytecodeParser parent, boolean duringCall) {
-        if (outerFrameState == null && parent != null) {
-            outerFrameState = parent.getFrameState().create(parent.bci(), null);
-        }
-        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
-            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
-            return newFrameState;
-        }
-        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-        return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
-    }
-
-    public BytecodePosition createBytecodePosition(int bci) {
-        BytecodeParser parent = parser.getParent();
-        if (AbstractBytecodeParser.Options.HideSubstitutionStates.getValue()) {
-            if (parser.parsingIntrinsic()) {
-                // Attribute to the method being replaced
-                return new BytecodePosition(parent.getFrameState().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
-            }
-            // Skip intrinsic frames
-            parent = (BytecodeParser) parser.getNonReplacementAncestor();
-        }
-        return create(null, bci, parent);
-    }
-
-    private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) {
-        BytecodePosition outer = o;
-        if (outer == null && parent != null) {
-            outer = parent.getFrameState().createBytecodePosition(parent.bci());
-        }
-        if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
-            return FrameState.toBytecodePosition(outerFrameState);
-        }
-        if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-        return new BytecodePosition(outer, method, bci);
-    }
-
-    public HIRFrameStateBuilder copy() {
-        return new HIRFrameStateBuilder(this);
-    }
-
-    public boolean isCompatibleWith(HIRFrameStateBuilder other) {
-        assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
-        assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
-
-        if (stackSize() != other.stackSize()) {
-            return false;
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode x = stackAt(i);
-            ValueNode y = other.stackAt(i);
-            if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) {
-                return false;
-            }
-        }
-        if (lockedObjects.length != other.lockedObjects.length) {
-            return false;
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) {
-                throw new BailoutException("unbalanced monitors");
-            }
-        }
-        return true;
-    }
-
-    public void merge(AbstractMergeNode block, HIRFrameStateBuilder other) {
-        assert isCompatibleWith(other);
-
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode curLocal = localAt(i);
-            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
-            if (curLocal != mergedLocal) {
-                storeLocal(i, mergedLocal);
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode curStack = stackAt(i);
-            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
-            if (curStack != mergedStack) {
-                storeStack(i, mergedStack);
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
-            assert monitorIds[i] == other.monitorIds[i];
-        }
-
-        if (sideEffects == null) {
-            sideEffects = other.sideEffects;
-        } else {
-            if (other.sideEffects != null) {
-                sideEffects.addAll(other.sideEffects);
-            }
-        }
-    }
-
-    private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
-        if (currentValue == null || currentValue.isDeleted()) {
-            return null;
-        } else if (block.isPhiAtMerge(currentValue)) {
-            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
-                propagateDelete((ValuePhiNode) currentValue);
-                return null;
-            }
-            ((PhiNode) currentValue).addInput(otherValue);
-            return currentValue;
-        } else if (currentValue != otherValue) {
-            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
-            if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
-                return null;
-            }
-            return createValuePhi(currentValue, otherValue, block);
-        } else {
-            return currentValue;
-        }
-    }
-
-    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
-        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
-        for (int i = 0; i < block.phiPredecessorCount(); i++) {
-            phi.addInput(currentValue);
-        }
-        phi.addInput(otherValue);
-        assert phi.valueCount() == block.phiPredecessorCount() + 1;
-        return phi;
-    }
-
-    private void propagateDelete(FloatingNode node) {
-        assert node instanceof ValuePhiNode || node instanceof ProxyNode;
-        if (node.isDeleted()) {
-            return;
-        }
-        // Collect all phi functions that use this phi so that we can delete them recursively (after
-        // we delete ourselves to avoid circles).
-        List<FloatingNode> propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot();
-
-        // Remove the phi function from all FrameStates where it is used and then delete it.
-        assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
-        node.replaceAtUsages(null);
-        node.safeDelete();
-
-        for (FloatingNode phiUsage : propagateUsages) {
-            propagateDelete(phiUsage);
-        }
-    }
-
-    public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin) {
-        for (int i = 0; i < localsSize(); i++) {
-            if (loopBegin.graph().isOSR() || liveness.localIsChangedInLoop(loopId, i)) {
-                storeLocal(i, createLoopPhi(loopBegin, localAt(i)));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            storeStack(i, createLoopPhi(loopBegin, stackAt(i)));
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]);
-        }
-    }
-
-    public void insertLoopProxies(LoopExitNode loopExit, HIRFrameStateBuilder loopEntryState) {
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, loopExit, graph));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, loopExit, graph));
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            ValueNode value = lockedObjects[i];
-            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
-                Debug.log(" inserting proxy for %s", value);
-                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
-            }
-        }
-    }
-
-    public void insertProxies(AbstractBeginNode begin) {
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode value = localAt(i);
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                storeLocal(i, ProxyNode.forValue(value, begin, graph));
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode value = stackAt(i);
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                storeStack(i, ProxyNode.forValue(value, begin, graph));
-            }
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            ValueNode value = lockedObjects[i];
-            if (value != null) {
-                Debug.log(" inserting proxy for %s", value);
-                lockedObjects[i] = ProxyNode.forValue(value, begin, graph);
-            }
-        }
-    }
-
-    private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value) {
-        if (value == null) {
-            return null;
-        }
-        assert !block.isPhiAtMerge(value) : "phi function for this block already created";
-
-        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(value.stamp().unrestricted(), block));
-        phi.addInput(value);
-        return phi;
-    }
-
-    /**
-     * Adds a locked monitor to this frame state.
-     *
-     * @param object the object whose monitor will be locked.
-     */
-    public void pushLock(ValueNode object, MonitorIdNode monitorId) {
-        assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object;
-        lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1);
-        monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1);
-        lockedObjects[lockedObjects.length - 1] = object;
-        monitorIds[monitorIds.length - 1] = monitorId;
-        assert lockedObjects.length == monitorIds.length;
-    }
-
-    /**
-     * Removes a locked monitor from this frame state.
-     *
-     * @return the object whose monitor was removed from the locks list.
-     */
-    public ValueNode popLock() {
-        try {
-            return lockedObjects[lockedObjects.length - 1];
-        } finally {
-            lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1);
-            monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1);
-            assert lockedObjects.length == monitorIds.length;
-        }
-    }
-
-    public MonitorIdNode peekMonitorId() {
-        return monitorIds[monitorIds.length - 1];
-    }
-
-    /**
-     * @return the current lock depth
-     */
-    public int lockDepth() {
-        assert lockedObjects.length == monitorIds.length;
-        return lockedObjects.length;
-    }
-
-    public boolean contains(ValueNode value) {
-        for (int i = 0; i < localsSize(); i++) {
-            if (localAt(i) == value) {
-                return true;
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            if (stackAt(i) == value) {
-                return true;
-            }
-        }
-        assert lockedObjects.length == monitorIds.length;
-        for (int i = 0; i < lockedObjects.length; i++) {
-            if (lockedObjects[i] == value || monitorIds[i] == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
-        /*
-         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
-         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
-         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
-         * Kind.Illegal, because the conflicting branch might not have been parsed.
-         */
-        if (liveness == null) {
-            return;
-        }
-        if (liveIn) {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveIn(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        } else {
-            for (int i = 0; i < locals.length; i++) {
-                if (!liveness.localIsLiveOut(block, i)) {
-                    locals[i] = null;
-                }
-            }
-        }
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public boolean rethrowException() {
-        return rethrowException;
-    }
-
-    /**
-     * @see BytecodeFrame#rethrowException
-     */
-    public void setRethrowException(boolean b) {
-        rethrowException = b;
-    }
-
-    /**
-     * Returns the size of the local variables.
-     *
-     * @return the size of the local variables
-     */
-    public int localsSize() {
-        return locals.length;
-    }
-
-    /**
-     * Gets the current size (height) of the stack.
-     */
-    public int stackSize() {
-        return stackSize;
-    }
-
-    /**
-     * Gets the value in the local variables at the specified index, without any sanity checking.
-     *
-     * @param i the index into the locals
-     * @return the instruction that produced the value for the specified local
-     */
-    public ValueNode localAt(int i) {
-        return locals[i];
-    }
-
-    /**
-     * Get the value on the stack at the specified stack index.
-     *
-     * @param i the index into the stack, with {@code 0} being the bottom of the stack
-     * @return the instruction at the specified position in the stack
-     */
-    public ValueNode stackAt(int i) {
-        return stack[i];
-    }
-
-    /**
-     * Gets the value in the lock at the specified index, without any sanity checking.
-     *
-     * @param i the index into the lock
-     * @return the instruction that produced the value for the specified lock
-     */
-    public ValueNode lockAt(int i) {
-        return lockedObjects[i];
-    }
-
-    public void storeLock(int i, ValueNode lock) {
-        lockedObjects[i] = lock;
-    }
-
-    /**
-     * Loads the local variable at the specified index, checking that the returned value is non-null
-     * and that two-stack values are properly handled.
-     *
-     * @param i the index of the local variable to load
-     * @return the instruction that produced the specified local
-     */
-    public ValueNode loadLocal(int i) {
-        ValueNode x = locals[i];
-        assert assertLoadLocal(i, x);
-        return x;
-    }
-
-    private boolean assertLoadLocal(int i, ValueNode x) {
-        assert x != null : i;
-        assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
-        assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
-        return true;
-    }
-
-    public void storeLocal(int i, ValueNode x) {
-        storeLocal(i, x, x == null ? null : x.getKind());
-    }
-
-    /**
-     * Stores a given local variable at the specified index. If the value occupies two slots, then
-     * the next local variable index is also overwritten.
-     *
-     * @param i the index at which to store
-     * @param x the instruction which produces the value for the local
-     */
-    public void storeLocal(int i, ValueNode x, Kind kind) {
-        assert assertStoreLocal(x);
-        locals[i] = x;
-        if (x != null) {
-            if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) {
-                // if this is a double word, then kill i+1
-                locals[i + 1] = null;
-            }
-            if (i > 0 && !parser.parsingIntrinsic()) {
-                ValueNode p = locals[i - 1];
-                if (p != null && p.getKind().needsTwoSlots()) {
-                    // if there was a double word at i - 1, then kill it
-                    locals[i - 1] = null;
-                }
-            }
-        }
-    }
-
-    private boolean assertStoreLocal(ValueNode x) {
-        assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
-        return true;
-    }
-
-    public void storeStack(int i, ValueNode x) {
-        assert assertStoreStack(i, x);
-        stack[i] = x;
-    }
-
-    private boolean assertStoreStack(int i, ValueNode x) {
-        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
-        return true;
-    }
-
-    /**
-     * Pushes an instruction onto the stack with the expected type.
-     *
-     * @param kind the type expected for this instruction
-     * @param x the instruction to push onto the stack
-     */
-    public void push(Kind kind, ValueNode x) {
-        assert assertPush(kind, x);
-        xpush(x);
-        if (kind.needsTwoSlots()) {
-            xpush(null);
-        }
-    }
-
-    private boolean assertPush(Kind kind, ValueNode x) {
-        assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
-        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack without checking the type.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void xpush(ValueNode x) {
-        assert assertXpush(x);
-        stack[stackSize++] = x;
-    }
-
-    private boolean assertXpush(ValueNode x) {
-        assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
-        return true;
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an int.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void ipush(ValueNode x) {
-        assert assertInt(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a float.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void fpush(ValueNode x) {
-        assert assertFloat(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is an object.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void apush(ValueNode x) {
-        assert assertObject(x);
-        xpush(x);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a long.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void lpush(ValueNode x) {
-        assert assertLong(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    /**
-     * Pushes a value onto the stack and checks that it is a double.
-     *
-     * @param x the instruction to push onto the stack
-     */
-    public void dpush(ValueNode x) {
-        assert assertDouble(x);
-        xpush(x);
-        xpush(null);
-    }
-
-    public void pushReturn(Kind kind, ValueNode x) {
-        if (kind != Kind.Void) {
-            push(kind.getStackKind(), x);
-        }
-    }
-
-    /**
-     * Pops an instruction off the stack with the expected type.
-     *
-     * @param kind the expected type
-     * @return the instruction on the top of the stack
-     */
-    public ValueNode pop(Kind kind) {
-        if (kind.needsTwoSlots()) {
-            xpop();
-        }
-        assert assertPop(kind);
-        return xpop();
-    }
-
-    private boolean assertPop(Kind kind) {
-        assert kind != Kind.Void;
-        ValueNode x = xpeek();
-        assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind);
-        return true;
-    }
-
-    /**
-     * Pops a value off of the stack without checking the type.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode xpop() {
-        return stack[--stackSize];
-    }
-
-    public ValueNode xpeek() {
-        return stack[stackSize - 1];
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an int.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode ipop() {
-        assert assertIntPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a float.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode fpop() {
-        assert assertFloatPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is an object.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode apop() {
-        assert assertObjectPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a long.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode lpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertLongPeek();
-        return xpop();
-    }
-
-    /**
-     * Pops a value off of the stack and checks that it is a double.
-     *
-     * @return x the instruction popped off the stack
-     */
-    public ValueNode dpop() {
-        assert assertHighPeek();
-        xpop();
-        assert assertDoublePeek();
-        return xpop();
-    }
-
-    /**
-     * Pop the specified number of slots off of this stack and return them as an array of
-     * instructions.
-     *
-     * @return an array containing the arguments off of the stack
-     */
-    public ValueNode[] popArguments(int argSize) {
-        ValueNode[] result = allocateArray(argSize);
-        int newStackSize = stackSize;
-        for (int i = argSize - 1; i >= 0; i--) {
-            newStackSize--;
-            if (stack[newStackSize] == null) {
-                /* Two-slot value. */
-                newStackSize--;
-                assert stack[newStackSize].getKind().needsTwoSlots();
-            } else {
-                assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1);
-            }
-            result[i] = stack[newStackSize];
-        }
-        stackSize = newStackSize;
-        return result;
-    }
-
-    /**
-     * Peeks an element from the operand stack.
-     *
-     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
-     *            top). Long and double arguments only count as one argument, i.e., null-slots are
-     *            ignored.
-     * @return The peeked argument.
-     */
-    public ValueNode peek(int argumentNumber) {
-        int idx = stackSize() - 1;
-        for (int i = 0; i < argumentNumber; i++) {
-            if (stackAt(idx) == null) {
-                idx--;
-                assert stackAt(idx).getKind().needsTwoSlots();
-            }
-            idx--;
-        }
-        return stackAt(idx);
-    }
-
-    /**
-     * Clears all values on this stack.
-     */
-    public void clearStack() {
-        stackSize = 0;
-    }
-
-    private boolean assertLongPeek() {
-        return assertLong(xpeek());
-    }
-
-    private static boolean assertLong(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Long);
-        return true;
-    }
-
-    private boolean assertIntPeek() {
-        return assertInt(xpeek());
-    }
-
-    private static boolean assertInt(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Int);
-        return true;
-    }
-
-    private boolean assertFloatPeek() {
-        return assertFloat(xpeek());
-    }
-
-    private static boolean assertFloat(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Float);
-        return true;
-    }
-
-    private boolean assertObjectPeek() {
-        return assertObject(xpeek());
-    }
-
-    private boolean assertObject(ValueNode x) {
-        assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object));
-        return true;
-    }
-
-    private boolean assertDoublePeek() {
-        return assertDouble(xpeek());
-    }
-
-    private static boolean assertDouble(ValueNode x) {
-        assert x != null && (x.getKind() == Kind.Double);
-        return true;
-    }
-
-    private boolean assertHighPeek() {
-        assert xpeek() == null;
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = hashCode(locals, locals.length);
-        result *= 13;
-        result += hashCode(stack, this.stackSize);
-        return result;
-    }
-
-    private static int hashCode(Object[] a, int length) {
-        int result = 1;
-        for (int i = 0; i < length; ++i) {
-            Object element = a[i];
-            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
-        }
-        return result;
-    }
-
-    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
-        for (int i = 0; i < length; ++i) {
-            if (a[i] != b[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean equals(Object otherObject) {
-        if (otherObject instanceof HIRFrameStateBuilder) {
-            HIRFrameStateBuilder other = (HIRFrameStateBuilder) otherObject;
-            if (!other.method.equals(method)) {
-                return false;
-            }
-            if (other.stackSize != stackSize) {
-                return false;
-            }
-            if (other.parser != parser) {
-                return false;
-            }
-            if (other.rethrowException != rethrowException) {
-                return false;
-            }
-            if (other.graph != graph) {
-                return false;
-            }
-            if (other.locals.length != locals.length) {
-                return false;
-            }
-            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
-                            equals(other.monitorIds, monitorIds, monitorIds.length);
-        }
-        return false;
-    }
-
-    public void replace(ValueNode oldValue, ValueNode newValue) {
-        for (int i = 0; i < locals.length; i++) {
-            if (locals[i] == oldValue) {
-                locals[i] = newValue;
-            }
-        }
-        for (int i = 0; i < stackSize; i++) {
-            if (stack[i] == oldValue) {
-                stack[i] = newValue;
-            }
-        }
-    }
-
-    @Override
-    public boolean isAfterSideEffect() {
-        return sideEffects != null;
-    }
-
-    @Override
-    public Iterable<StateSplit> sideEffects() {
-        return sideEffects;
-    }
-
-    @Override
-    public void addSideEffect(StateSplit sideEffect) {
-        assert sideEffect != null;
-        assert sideEffect.hasSideEffect();
-        if (sideEffects == null) {
-            sideEffects = new ArrayList<>(4);
-        }
-        sideEffects.add(sideEffect);
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Fri May 15 11:55:52 2015 +0200
@@ -71,9 +71,13 @@
     }
 
     @Opcode("CALL_DIRECT")
-    public abstract static class DirectCallOp extends MethodCallOp {
+    public static class DirectCallOp extends MethodCallOp {
         public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
 
+        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, state);
+        }
+
         protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
             super(c, callTarget, result, parameters, temps, state);
         }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri May 15 11:55:52 2015 +0200
@@ -38,13 +38,12 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
-import com.oracle.graal.lir.amd64.AMD64Call.CallOp;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64ControlFlow {
 
     public static final class ReturnOp extends AMD64LIRInstruction implements BlockEndOp {
-        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
         @Use({REG, ILLEGAL}) protected Value x;
 
         public ReturnOp(Value x) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri May 15 11:55:52 2015 +0200
@@ -39,7 +39,7 @@
  * such fields.</li>
  * </ul>
  */
-public final class CompositeValueClass<T> {
+public final class CompositeValueClass<T> extends FieldIntrospection<T> {
 
     /**
      * The CompositeValueClass is only used for formatting for the most part so cache it as a
@@ -56,16 +56,15 @@
 
     };
 
-    public static CompositeValueClass<?> get(Class<?> type) {
-        return compositeClass.get(type);
+    @SuppressWarnings("unchecked")
+    public static <T> CompositeValueClass<T> get(Class<T> type) {
+        return (CompositeValueClass<T>) compositeClass.get(type);
     }
 
-    private final Class<?> clazz;
     private final Values values;
-    private final Fields data;
 
     private CompositeValueClass(Class<T> clazz) {
-        this.clazz = clazz;
+        super(clazz);
 
         CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset());
         vfs.scan(clazz, CompositeValue.class, false);
@@ -94,9 +93,14 @@
     }
 
     @Override
+    public Fields[] getAllFields() {
+        return new Fields[]{data, values};
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" components[");
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
         values.appendFields(str);
         str.append("] data[");
         data.appendFields(str);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri May 15 11:55:52 2015 +0200
@@ -76,6 +76,17 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
+    public static <T> LIRInstructionClass<T> get(Class<T> clazz) {
+        try {
+            Field field = clazz.getDeclaredField("TYPE");
+            field.setAccessible(true);
+            return (LIRInstructionClass<T>) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {
 
         private String opcodeConstant;
@@ -137,7 +148,7 @@
             if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
-                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type));
+                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass()));
             } else {
                 super.scanField(field, offset);
             }
@@ -151,6 +162,12 @@
     }
 
     @Override
+    public Fields[] getAllFields() {
+        assert values == null;
+        return new Fields[]{data, uses, alives, temps, defs, states};
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri May 15 11:55:52 2015 +0200
@@ -100,8 +100,8 @@
 
         final EnumSet<OperandFlag> flags;
 
-        public ValueFieldInfo(long offset, String name, Class<?> type, EnumSet<OperandFlag> flags) {
-            super(offset, name, type);
+        public ValueFieldInfo(long offset, String name, Class<?> type, Class<?> declaringClass, EnumSet<OperandFlag> flags) {
+            super(offset, name, type, declaringClass);
             assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type);
             this.flags = flags;
         }
@@ -171,14 +171,14 @@
                 assert annotation != null : "Field must have operand mode annotation: " + field;
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type, flags);
-                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
                 annotation.directCount++;
             } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type.getComponentType(), flags);
-                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags));
             } else {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Fri May 15 11:55:52 2015 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -123,8 +123,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Input list field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Input list field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input list field must not be public");
                         }
                     } else {
                         if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {
@@ -133,8 +133,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Input field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Input field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Input field must not be public");
                         }
                     }
                 } else if (isSuccessor) {
@@ -152,8 +152,8 @@
                         if (modifiers.contains(FINAL)) {
                             throw new ElementException(field, "Successor field must not be final");
                         }
-                        if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) {
-                            throw new ElementException(field, "Successor field must be protected or package-private");
+                        if (modifiers.contains(PUBLIC)) {
+                            throw new ElementException(field, "Successor field must not be public");
                         }
                     }
 
@@ -167,12 +167,8 @@
                     if (isAssignableWithErasure(field, NodeSuccessorList)) {
                         throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName());
                     }
-                    if (modifiers.contains(PUBLIC)) {
-                        if (!modifiers.contains(FINAL)) {
-                            throw new ElementException(field, "Data field must be final if public otherwise it must be protected");
-                        }
-                    } else if (!modifiers.contains(PROTECTED)) {
-                        throw new ElementException(field, "Data field must be protected");
+                    if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) {
+                        throw new ElementException(field, "Data field must be final if public");
                     }
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,10 +31,14 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public abstract class DirectCallTargetNode extends LoweredCallTargetNode {
+public class DirectCallTargetNode extends LoweredCallTargetNode {
 
     public static final NodeClass<DirectCallTargetNode> TYPE = NodeClass.create(DirectCallTargetNode.class);
 
+    public DirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        this(TYPE, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
     protected DirectCallTargetNode(NodeClass<? extends DirectCallTargetNode> c, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
                     CallingConvention.Type callType, InvokeKind invokeKind) {
         super(c, arguments, returnStamp, signature, target, callType, invokeKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Fri May 15 11:55:52 2015 +0200
@@ -32,7 +32,6 @@
 import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.util.*;
 
 /**
  * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for
@@ -1154,32 +1153,14 @@
         }
     }
 
+    /**
+     * Removes unnecessary nodes from the graph after decoding.
+     *
+     * @param methodScope The current method.
+     * @param start Marker for the begin of the current method in the graph.
+     */
     protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         assert verifyEdges(methodScope);
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (node instanceof MergeNode) {
-                MergeNode mergeNode = (MergeNode) node;
-                if (mergeNode.forwardEndCount() == 1) {
-                    methodScope.graph.reduceTrivialMerge(mergeNode);
-                }
-            }
-        }
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
-                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
-                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
-                    node.safeDelete();
-                }
-            }
-        }
-
-        for (Node node : methodScope.graph.getNewNodes(start)) {
-            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
-                GraphUtil.killCFG(node);
-            }
-        }
     }
 
     protected boolean verifyEdges(MethodScope methodScope) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,11 +31,16 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public abstract class IndirectCallTargetNode extends LoweredCallTargetNode {
+public class IndirectCallTargetNode extends LoweredCallTargetNode {
     public static final NodeClass<IndirectCallTargetNode> TYPE = NodeClass.create(IndirectCallTargetNode.class);
 
     @Input protected ValueNode computedAddress;
 
+    public IndirectCallTargetNode(ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType,
+                    InvokeKind invokeKind) {
+        this(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
+    }
+
     protected IndirectCallTargetNode(NodeClass<? extends IndirectCallTargetNode> c, ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature,
                     ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
         super(c, arguments, returnStamp, signature, target, callType, invokeKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Fri May 15 11:55:52 2015 +0200
@@ -79,6 +79,30 @@
     protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         GraphUtil.normalizeLoops(methodScope.graph);
         super.cleanupGraph(methodScope, start);
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.forwardEndCount() == 1) {
+                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
+                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
+                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
+                    node.safeDelete();
+                }
+            }
+        }
+
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
+                GraphUtil.killCFG(node);
+            }
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Fri May 15 11:55:52 2015 +0200
@@ -59,6 +59,10 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.meet(values()));
+        Stamp valuesStamp = StampTool.meet(values());
+        if (stamp.isCompatible(valuesStamp)) {
+            valuesStamp = stamp.join(valuesStamp);
+        }
+        return updateStamp(valuesStamp);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,11 +31,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
-public final class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
     public static final NodeClass<IntegerDivNode> TYPE = NodeClass.create(IntegerDivNode.class);
 
     public IntegerDivNode(ValueNode x, ValueNode y) {
-        super(TYPE, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected IntegerDivNode(NodeClass<? extends IntegerDivNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,11 +31,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public final class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
     public static final NodeClass<IntegerRemNode> TYPE = NodeClass.create(IntegerRemNode.class);
 
     public IntegerRemNode(ValueNode x, ValueNode y) {
-        super(TYPE, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected IntegerRemNode(NodeClass<? extends IntegerRemNode> c, ValueNode x, ValueNode y) {
+        super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,12 +31,16 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|/|")
-public final class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
     public static final NodeClass<UnsignedDivNode> TYPE = NodeClass.create(UnsignedDivNode.class);
 
     public UnsignedDivNode(ValueNode x, ValueNode y) {
-        super(TYPE, x.stamp().unrestricted(), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedDivNode(NodeClass<? extends UnsignedDivNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Fri May 15 11:55:52 2015 +0200
@@ -31,12 +31,16 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "|%|")
-public final class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
 
     public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
 
     public UnsignedRemNode(ValueNode x, ValueNode y) {
-        super(TYPE, x.stamp().unrestricted(), x, y);
+        this(TYPE, x, y);
+    }
+
+    protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y) {
+        super(c, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Fri May 15 11:55:52 2015 +0200
@@ -47,10 +47,7 @@
     protected int bci = BytecodeFrame.UNKNOWN_BCI;
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
-        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
-        this.arguments = new NodeInputList<>(this, arguments);
-        this.descriptor = descriptor;
-        this.foreignCalls = foreignCalls;
+        this(TYPE, foreignCalls, descriptor, arguments);
     }
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
@@ -67,9 +64,9 @@
         this.foreignCalls = foreignCalls;
     }
 
-    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
-        super(c, stamp);
-        this.arguments = new NodeInputList<>(this);
+    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(c, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri May 15 11:55:52 2015 +0200
@@ -41,7 +41,7 @@
  * Implements a type check against a compile-time known type.
  */
 @NodeInfo
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
+public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
 
     public static final NodeClass<CheckCastNode> TYPE = NodeClass.create(CheckCastNode.class);
     @Input protected ValueNode object;
@@ -55,7 +55,11 @@
     protected final boolean forStoreCheck;
 
     public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
-        super(TYPE, StampFactory.declaredTrusted(type));
+        this(TYPE, type, object, profile, forStoreCheck);
+    }
+
+    protected CheckCastNode(NodeClass<? extends CheckCastNode> c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
+        super(c, StampFactory.declaredTrusted(type));
         assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp();
         assert type != null;
         this.type = type;
@@ -178,7 +182,7 @@
         return this;
     }
 
-    private static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) {
+    protected static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) {
         ResolvedJavaType objectType = StampTool.typeOrNull(object);
         if (objectType != null && type.isAssignableFrom(objectType)) {
             // we don't have to check for null types here because they will also pass the
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri May 15 11:55:52 2015 +0200
@@ -36,14 +36,18 @@
  * The {@code InstanceOfNode} represents an instanceof test.
  */
 @NodeInfo
-public final class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
+public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
     public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
 
     protected final ResolvedJavaType type;
     protected JavaTypeProfile profile;
 
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
-        super(TYPE, object);
+        this(TYPE, type, object, profile);
+    }
+
+    protected InstanceOfNode(NodeClass<? extends InstanceOfNode> c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        super(c, object);
         this.type = type;
         this.profile = profile;
         assert type != null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri May 15 11:55:52 2015 +0200
@@ -175,7 +175,7 @@
              * interface methods calls.
              */
             if (declaredReceiverType.isInterface()) {
-                tryCheckCastSingleImplementor(receiver, declaredReceiverType);
+                tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, declaredReceiverType);
             }
 
             if (receiver instanceof UncheckedInterfaceProvider) {
@@ -184,14 +184,22 @@
                 if (uncheckedStamp != null) {
                     ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp);
                     if (uncheckedReceiverType.isInterface()) {
-                        tryCheckCastSingleImplementor(receiver, uncheckedReceiverType);
+                        tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, uncheckedReceiverType);
                     }
                 }
             }
         }
     }
 
-    private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) {
+    private void tryCheckCastSingleImplementor(Assumptions assumptions, ValueNode receiver, ResolvedJavaType declaredReceiverType) {
+        if (assumptions == null) {
+            /*
+             * Even though we are not registering an assumption (see comment below), the
+             * optimization is only valid when speculative optimizations are enabled.
+             */
+            return;
+        }
+
         ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
         if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
             ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri May 15 11:55:52 2015 +0200
@@ -37,13 +37,17 @@
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
-public final class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
+public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
 
     public static final NodeClass<NewInstanceNode> TYPE = NodeClass.create(NewInstanceNode.class);
     protected final ResolvedJavaType instanceClass;
 
     public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
-        super(TYPE, StampFactory.exactNonNull(type), fillContents);
+        this(TYPE, type, fillContents);
+    }
+
+    protected NewInstanceNode(NodeClass<? extends NewInstanceNode> c, ResolvedJavaType type, boolean fillContents) {
+        super(c, StampFactory.exactNonNull(type), fillContents);
         assert !type.isArray() && !type.isInterface() && !type.isPrimitive();
         this.instanceClass = type;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Fri May 15 11:55:52 2015 +0200
@@ -33,7 +33,7 @@
  * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array.
  */
 @NodeInfo
-public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
+public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
 
     public static final NodeClass<NewMultiArrayNode> TYPE = NodeClass.create(NewMultiArrayNode.class);
     @Input protected NodeInputList<ValueNode> dimensions;
@@ -52,7 +52,11 @@
     }
 
     public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) {
-        super(TYPE, StampFactory.exactNonNull(type));
+        this(TYPE, type, dimensions);
+    }
+
+    protected NewMultiArrayNode(NodeClass<? extends NewMultiArrayNode> c, ResolvedJavaType type, ValueNode[] dimensions) {
+        super(c, StampFactory.exactNonNull(type));
         this.type = type;
         this.dimensions = new NodeInputList<>(this, dimensions);
         assert dimensions.length > 0 && type.isArray();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 15 11:55:52 2015 +0200
@@ -68,10 +68,14 @@
         ObjectStamp objectStamp = (ObjectStamp) object.stamp();
         if (objectStamp.isExactType()) {
             return objectStamp.type().hasFinalizer();
-        } else if (objectStamp.type() != null && assumptions != null) {
+        } else if (objectStamp.type() != null) {
             AssumptionResult<Boolean> result = objectStamp.type().hasFinalizableSubclass();
-            assumptions.record(result);
-            return result.getResult();
+            if (result.isAssumptionFree()) {
+                return result.getResult();
+            } else if (assumptions != null) {
+                assumptions.record(result);
+                return result.getResult();
+            }
         }
         return true;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Fri May 15 11:55:52 2015 +0200
@@ -33,14 +33,18 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
-public final class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
+public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
 
     public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
     protected final ResolvedJavaType componentType;
     protected final int length;
 
     public VirtualArrayNode(ResolvedJavaType componentType, int length) {
-        super(TYPE, componentType.getArrayClass(), true);
+        this(TYPE, componentType, length);
+    }
+
+    protected VirtualArrayNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType componentType, int length) {
+        super(c, componentType.getArrayClass(), true);
         this.componentType = componentType;
         this.length = length;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java	Fri May 15 11:55:52 2015 +0200
@@ -70,6 +70,31 @@
         return false;
     }
 
+    /**
+     * Removes the first instance of the given phase class, looking recursively into inner phase
+     * suites.
+     */
+    public boolean removePhase(Class<? extends BasePhase<? super C>> phaseClass) {
+        ListIterator<BasePhase<? super C>> it = phases.listIterator();
+        while (it.hasNext()) {
+            BasePhase<? super C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                it.remove();
+                return true;
+            } else if (phase instanceof PhaseSuite) {
+                @SuppressWarnings("unchecked")
+                PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
+                if (innerSuite.removePhase(phaseClass)) {
+                    if (innerSuite.phases.isEmpty()) {
+                        it.remove();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     protected void run(StructuredGraph graph, C context) {
         for (BasePhase<? super C> phase : phases) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Fri May 15 11:55:52 2015 +0200
@@ -412,4 +412,23 @@
         test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"});
         test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"});
     }
+
+    public int conditionalInstantiation(Object o) {
+        int total = 0;
+        if (o instanceof CharSequence) {
+            if (o instanceof StringBuilder || o instanceof String) {
+                total = 9;
+            }
+            total += (o instanceof String ? 2 : 1);
+        }
+
+        return total;
+    }
+
+    @Test
+    public void testInstantiation() {
+        test("conditionalInstantiation", "foo");
+        test("conditionalInstantiation", new StringBuilder());
+        test("conditionalInstantiation", 1);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -148,12 +148,12 @@
             /*
              * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the
              * case that the foreign call can deoptimize. As with all deoptimization, we need a
-             * state in a normal method as opposed to an intrinsic.
+             * state in a non-intrinsic method.
              */
-            GraphBuilderContext ancestor = b.getNonReplacementAncestor();
-            if (ancestor != null) {
+            GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor();
+            if (nonIntrinsicAncestor != null) {
                 ForeignCallNode foreign = (ForeignCallNode) res;
-                foreign.setBci(ancestor.bci());
+                foreign.setBci(nonIntrinsicAncestor.bci());
             }
         }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graphbuilderconf.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Fri May 15 11:55:52 2015 +0200
@@ -143,13 +143,8 @@
         ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
         ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
         ConstantLocationNode location = createFieldLocation(graph, field, false);
+        assert location != null;
 
-        if (location == null) {
-            /* Field has been eliminated, so no write necessary. */
-            assert !storeField.isVolatile() : "missing memory barriers";
-            graph.removeFixed(storeField);
-            return;
-        }
         WriteNode memoryWrite = graph.add(new WriteNode(object, value, location, fieldStoreBarrierType(storeField.field())));
         memoryWrite.setStateAfter(storeField.stateAfter());
         graph.replaceFixedWithFixed(storeField, memoryWrite);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Fri May 15 11:55:52 2015 +0200
@@ -91,7 +91,7 @@
     }
 
     public <T extends ValueNode> T changeToWord(T node) {
-        if (wordTypes.isWord(node)) {
+        if (wordTypes != null && wordTypes.isWord(node)) {
             node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node)));
         }
         return node;
@@ -125,8 +125,13 @@
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
      */
-    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         boolean isStatic = invokeKind == InvokeKind.Static;
+        ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic);
+        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+    }
+
+    public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, boolean isStatic) {
         ResolvedJavaMethod method = null;
         for (Method m : declaringClass.getDeclaredMethods()) {
             if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) {
@@ -135,14 +140,14 @@
             }
         }
         assert method != null : "did not find method in " + declaringClass + " named " + name;
-        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+        return method;
     }
 
     /**
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
      * arguments.
      */
-    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
         assert method.isStatic() == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
@@ -181,12 +186,14 @@
         }
         int argIndex = 0;
         if (!isStatic) {
-            Kind expected = wordTypes.asKind(method.getDeclaringClass());
+            ResolvedJavaType expectedType = method.getDeclaringClass();
+            Kind expected = wordTypes == null ? expectedType.getKind() : wordTypes.asKind(expectedType);
             Kind actual = args[argIndex++].stamp().getStackKind();
             assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]";
         }
         for (int i = 0; i != signature.getParameterCount(false); i++) {
-            Kind expected = wordTypes.asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind();
+            JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass());
+            Kind expected = wordTypes == null ? expectedType.getKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind();
             Kind actual = args[argIndex++].stamp().getStackKind();
             if (expected != actual) {
                 throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Fri May 15 11:55:52 2015 +0200
@@ -96,7 +96,17 @@
     protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) {
         InstanceOfUsageReplacer replacer;
         if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode || usage instanceof ConditionAnchorNode) {
-            replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage);
+            ValueNode trueValue = ConstantNode.forInt(1, graph);
+            ValueNode falseValue = ConstantNode.forInt(0, graph);
+            if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) {
+                /*
+                 * This code doesn't really care what values are used so adopt the values from the
+                 * previous instantiation.
+                 */
+                trueValue = instantiation.trueValue;
+                falseValue = instantiation.falseValue;
+            }
+            replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage);
         } else {
             assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
             ConditionalNode c = (ConditionalNode) usage;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.replacements.nodes.*;
+
+public class MethodHandleInvocationPlugin implements GenericInvocationPlugin {
+    private final MethodHandleAccessProvider methodHandleAccess;
+    private final GenericInvocationPlugin delegate;
+
+    public MethodHandleInvocationPlugin(MethodHandleAccessProvider methodHandleAccess, GenericInvocationPlugin delegate) {
+        this.methodHandleAccess = methodHandleAccess;
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method);
+        if (intrinsicMethod != null) {
+            InvokeKind invokeKind = b.getInvokeKind();
+            if (invokeKind != InvokeKind.Static) {
+                args[0] = b.nullCheckedValue(args[0]);
+            }
+            JavaType invokeReturnType = b.getInvokeReturnType();
+            InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args);
+            if (invoke == null) {
+                MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args);
+                if (invokeReturnType.getKind() == Kind.Void) {
+                    b.add(methodHandleNode);
+                } else {
+                    b.addPush(methodHandleNode);
+                }
+            } else {
+                CallTargetNode callTarget = invoke.callTarget();
+                NodeInputList<ValueNode> argumentsList = callTarget.arguments();
+                ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]);
+                for (ValueNode arg : newArgs) {
+                    b.recursiveAppend(arg);
+                }
+                b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs);
+            }
+            return true;
+        }
+        return delegate.apply(b, method, args);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Fri May 15 11:55:52 2015 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.compiler.common.GraalInternalError.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 
 import java.util.*;
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Fri May 15 11:55:52 2015 +0200
@@ -25,7 +25,7 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
 import static java.lang.String.*;
 
@@ -77,6 +77,10 @@
         this.graphBuilderPlugins = plugins;
     }
 
+    public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() {
+        return graphBuilderPlugins;
+    }
+
     protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
         return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null;
     }
@@ -581,7 +585,19 @@
                 if (args != null) {
                     plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection));
                 }
-                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE).apply(graph);
+
+                IntrinsicContext initialIntrinsicContext = null;
+                if (method.getAnnotation(Snippet.class) == null) {
+                    // Post-parse inlined intrinsic
+                    initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING);
+                } else {
+                    // Snippet
+                    ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
+                    initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING);
+                }
+
+                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(
+                                graph);
 
                 if (OptCanonicalizer.getValue()) {
                     new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
@@ -593,16 +609,7 @@
         }
 
         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts) {
-            IntrinsicContext initialIntrinsicContext = null;
-            if (method.getAnnotation(Snippet.class) == null) {
-                // Post-parse inlined intrinsic
-                initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING);
-            } else {
-                // Snippet
-                ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
-                initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING);
-            }
+                        OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
             return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Fri May 15 11:55:52 2015 +0200
@@ -1098,11 +1098,12 @@
             // rewire outgoing memory edges
             replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates));
 
-            ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
-            MemoryMapNode memoryMap = ret.getMemoryMap();
-            ret.setMemoryMap(null);
-            memoryMap.safeDelete();
-
+            if (returnNode != null) {
+                ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
+                MemoryMapNode memoryMap = ret.getMemoryMap();
+                ret.setMemoryMap(null);
+                memoryMap.safeDelete();
+            }
             if (memoryAnchor != null) {
                 // rewire incoming memory edges
                 MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+@NodeInfo
+public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
+    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
+
+    protected final IntrinsicMethod intrinsicMethod;
+
+    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) {
+        super(TYPE, invokeKind, targetMethod, bci, returnType, arguments);
+        this.intrinsicMethod = intrinsicMethod;
+    }
+
+    /**
+     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
+     * invocation on another method with possibly transformed arguments.
+     *
+     * @param assumptions object for recording any speculations made during the transformation
+     * @param methodHandleAccess objects for accessing the implementation internals of a
+     *            {@link MethodHandle}
+     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
+     * @param bci the BCI of the original {@link MethodHandle} call
+     * @param returnType return type of the original {@link MethodHandle} call
+     * @param arguments arguments to the original {@link MethodHandle} call
+     * @return a more direct invocation derived from the {@link MethodHandle} call or null
+     */
+    public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode... arguments) {
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
+        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
+        InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray);
+        if (invoke != null) {
+            assert invoke.graph() == null;
+            invoke = graph().addOrUniqueWithInputs(invoke);
+            invoke.setStateAfter(stateAfter());
+            FixedNode currentNext = next();
+            replaceAtUsages(invoke);
+            GraphUtil.removeFixedWithUnusedInputs(this);
+            graph().addBeforeFixed(currentNext, invoke);
+        }
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     *
+     * @return the receiver argument node
+     */
+    private static ValueNode getReceiver(ValueNode[] arguments) {
+        return arguments[0];
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     *
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private static ValueNode getMemberName(ValueNode[] arguments) {
+        return arguments[arguments.length - 1];
+    }
+
+    /**
+     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+     *
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode methodHandleNode = getReceiver(arguments);
+        if (methodHandleNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
+        }
+        return null;
+    }
+
+    /**
+     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+     * the member name argument is constant.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci,
+                    JavaType returnType, ValueNode[] arguments) {
+        ValueNode memberNameNode = getMemberName(arguments);
+        if (memberNameNode.isConstant()) {
+            return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the targetMethod of a
+     * java.lang.invoke.MemberName.
+     *
+     * @param target the target, already loaded from the member name node
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target,
+                    ResolvedJavaMethod original) {
+        if (target == null) {
+            return null;
+        }
+
+        // In lambda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        Signature signature = target.getSignature();
+        final boolean isStatic = target.isStatic();
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = target.getDeclaringClass();
+            maybeCastArgument(arguments, 0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
+            maybeCastArgument(arguments, receiverSkip + index, parameterType);
+        }
+
+        if (target.canBeStaticallyBound()) {
+            return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments);
+        }
+
+        // Try to get the most accurate receiver type
+        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+            ValueNode receiver = getReceiver(arguments);
+            ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp());
+            if (receiverType != null) {
+                AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(target);
+                if (concreteMethod != null) {
+                    assumptions.record(concreteMethod);
+                    return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
+                }
+            }
+        } else {
+            AssumptionResult<ResolvedJavaMethod> concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target);
+            if (concreteMethod != null) {
+                assumptions.record(concreteMethod);
+                return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     *
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            ResolvedJavaType targetType = (ResolvedJavaType) type;
+            if (!targetType.isPrimitive()) {
+                ValueNode argument = arguments[index];
+                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+                    PiNode piNode = new PiNode(argument, StampFactory.declared(targetType));
+                    arguments[index] = piNode;
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
+     *
+     * @return invoke node for the member name target
+     */
+    private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) {
+        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType targetReturnType = target.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] targetArguments;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                targetArguments = arguments;
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+
+        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType);
+
+        // The call target can have a different return type than the invoker,
+        // e.g. the target returns an Object but the invoker void. In this case
+        // we need to use the stamp of the invoker. Note: always using the
+        // invoker's stamp would be wrong because it's a less concrete type
+        // (usually java.lang.Object).
+        if (returnType.getKind() == Kind.Void) {
+            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
+        } else {
+            return new InvokeNode(callTarget, bci);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.nodes;
+
+import static sun.misc.Version.*;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * A call target that replaces itself in the graph when being lowered by restoring the original
+ * {@link MethodHandle} invocation target. Prior to
+ * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
+ * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
+ * that case, the original invocation must be restored with all of its original arguments. Why?
+ * HotSpot linkage for {@link MethodHandle} intrinsics (see
+ * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
+ * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
+ * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
+ * invocation drops these arguments which means the interpreter won't find them.
+ */
+@NodeInfo
+public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
+
+    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
+
+    /**
+     * Creates a call target for an invocation on a direct target derived by resolving a constant
+     * {@link MethodHandle}.
+     */
+    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
+            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
+            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType);
+        }
+        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
+    }
+
+    protected final ResolvedJavaMethod originalTargetMethod;
+    protected final JavaType originalReturnType;
+    @Input NodeInputList<ValueNode> originalArguments;
+
+    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
+                    ValueNode[] originalArguments, JavaType originalReturnType) {
+        super(TYPE, invokeKind, targetMethod, arguments, returnType);
+        this.originalTargetMethod = originalTargetMethod;
+        this.originalReturnType = originalReturnType;
+        this.originalArguments = new NodeInputList<>(this, originalArguments);
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        MethodCallTargetNode replacement = graph().add(
+                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType));
+
+        // Replace myself...
+        this.replaceAndDelete(replacement);
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        throw GraalInternalError.shouldNotReachHere("should have replaced itself");
+    }
+}
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Fri May 15 11:55:52 2015 +0200
@@ -74,7 +74,6 @@
         return new HotSpotTruffleRuntime();
     }
 
-    private TruffleCompilerImpl truffleCompiler;
     private Map<OptimizedCallTarget, Future<?>> compilations = newIdentityMap();
     private final ThreadPoolExecutor compileQueue;
 
@@ -213,21 +212,12 @@
     @Override
     public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) {
         if (truffleCompiler == null) {
-            truffleCompiler = new TruffleCompilerImpl();
+            truffleCompiler = DefaultTruffleCompiler.create();
         }
         Runnable r = new Runnable() {
             @Override
             public void run() {
-                boolean success = true;
-                try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
-                    truffleCompiler.compileMethod(optimizedCallTarget);
-                } catch (Throwable e) {
-                    optimizedCallTarget.notifyCompilationFailed(e);
-                    success = false;
-                } finally {
-                    optimizedCallTarget.notifyCompilationFinished(success);
-
-                }
+                doCompile(optimizedCallTarget);
             }
         };
         Future<?> future = compileQueue.submit(r);
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Fri May 15 11:55:52 2015 +0200
@@ -205,19 +205,19 @@
     }
 
     @Test
-    public void constantValueInertToolEvalNodeFactory() {
+    public void constantValueInertAdvancedInstrumentRootFactory() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe testProbe = result.probe();
-        // A factory that could insert a ToolEvalNode into the AST, but which never does.
-        Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
+        // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does.
+        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
 
-            public ToolEvalNode createToolEvalNode(Probe probe, Node node) {
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
                 return null;
             }
-        }, null);
+        }, null, "test AdvancedInstrument");
         testProbe.attach(instrument);
 
         // It all gets compiled away
@@ -225,29 +225,30 @@
     }
 
     @Test
-    public void constantValueInertToolEvalNode() {
+    public void constantValueInertAdvancedInstrumentRoot() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode resultTestNode = new ConstantTestNode(42);
         RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode);
         rootTestNode.adoptChildren();
         Probe testProbe = resultTestNode.probe();
-        // A factory that inserts a ToolEvalNode with empty methods into the instrumentation chain.
-        Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
+        // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation .
+        Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
 
-            public ToolEvalNode createToolEvalNode(Probe probe, Node node) {
-                return new ToolEvalNode() {
+            @Override
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) {
+                return new AdvancedInstrumentRoot() {
 
                     public String instrumentationInfo() {
                         return null;
                     }
 
                     @Override
-                    public Object executeToolEvalNode(Node n, VirtualFrame frame) {
+                    public Object executeRoot(Node n, VirtualFrame frame) {
                         return null;
                     }
                 };
             }
-        }, null);
+        }, null, "test AdvancedInstrument");
         testProbe.attach(instrument);
 
         // It all gets compiled away.
@@ -351,6 +352,7 @@
             final boolean[] isCurrentlyCompiled = {false};
             final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() {
 
+                @Override
                 public void notifyIsCompiled(boolean isCompiled) {
                     isCurrentlyCompiled[0] = isCompiled;
                 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Fri May 15 11:55:52 2015 +0200
@@ -38,12 +38,12 @@
 import com.oracle.truffle.api.nodes.*;
 
 public class PartialEvaluationTest extends GraalCompilerTest {
-    private final TruffleCompilerImpl truffleCompiler;
+    private final TruffleCompiler truffleCompiler;
 
     public PartialEvaluationTest() {
         // Make sure Truffle runtime is initialized.
         Assert.assertTrue(Truffle.getRuntime() != null);
-        this.truffleCompiler = new TruffleCompilerImpl();
+        this.truffleCompiler = DefaultTruffleCompiler.create();
 
         DebugEnvironment.initialize(System.out);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java	Fri May 15 11:55:52 2015 +0200
@@ -28,8 +28,6 @@
 
 public class CompilationProfile {
 
-    private static final int TIMESTAMP_THRESHOLD = Math.max(TruffleCompilationThreshold.getValue() / 2, 1);
-
     /**
      * Number of times an installed code for this tree was invalidated.
      */
@@ -112,7 +110,7 @@
         interpreterCallAndLoopCount++;
 
         int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
-        if (callsMissing == TIMESTAMP_THRESHOLD) {
+        if (callsMissing == getTimestampThreshold()) {
             timestamp = System.nanoTime();
         }
     }
@@ -130,7 +128,7 @@
     }
 
     public void deferCompilation() {
-        ensureProfiling(0, TIMESTAMP_THRESHOLD + 1);
+        ensureProfiling(0, getTimestampThreshold() + 1);
         timestamp = 0;
         deferedCount++;
     }
@@ -139,7 +137,7 @@
         interpreterCallAndLoopCount += count;
 
         int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount;
-        if (callsMissing <= TIMESTAMP_THRESHOLD && callsMissing + count > TIMESTAMP_THRESHOLD) {
+        if (callsMissing <= getTimestampThreshold() && callsMissing + count > getTimestampThreshold()) {
             timestamp = System.nanoTime();
         }
     }
@@ -154,4 +152,7 @@
         return timestamp;
     }
 
+    private static int getTimestampThreshold() {
+        return Math.max(TruffleCompilationThreshold.getValue() / 2, 1);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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.truffle;
+
+import java.util.*;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.java.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.runtime.*;
+
+public final class DefaultTruffleCompiler extends TruffleCompiler {
+
+    public static TruffleCompiler create() {
+        Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        Suites suites = backend.getSuites().getDefaultSuites();
+        LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites();
+        GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
+        Plugins plugins = phase.getGraphBuilderConfig().getPlugins();
+        return new DefaultTruffleCompiler(plugins, suites, lirSuites, backend);
+    }
+
+    private DefaultTruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) {
+        super(plugins, suites, lirSuites, backend);
+    }
+
+    @Override
+    protected PartialEvaluator createPartialEvaluator() {
+        return new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch);
+    }
+
+    @Override
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
+        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        iterator.remove();
+        iterator.add(new GraphBuilderPhase(config));
+        return suite;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Fri May 15 11:55:52 2015 +0200
@@ -31,6 +31,8 @@
 import com.oracle.graal.api.code.stack.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.truffle.debug.*;
 import com.oracle.graal.truffle.unsafe.*;
@@ -55,7 +57,8 @@
     private final List<GraalTruffleCompilationListener> compilationListeners = new ArrayList<>();
     private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener();
 
-    private LoopNodeFactory loopNodeFactory;
+    protected TruffleCompiler truffleCompiler;
+    protected LoopNodeFactory loopNodeFactory;
 
     public GraalTruffleRuntime() {
         Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
@@ -101,11 +104,14 @@
         if (!(repeatingNode instanceof Node)) {
             throw new IllegalArgumentException("Repeating node must be of type Node.");
         }
+        return getLoopNodeFactory().create(repeatingNode);
+    }
+
+    protected LoopNodeFactory getLoopNodeFactory() {
         if (loopNodeFactory == null) {
             loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class);
         }
-
-        return loopNodeFactory.create(repeatingNode);
+        return loopNodeFactory;
     }
 
     @Override
@@ -271,6 +277,18 @@
 
     public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous);
 
+    protected void doCompile(OptimizedCallTarget optimizedCallTarget) {
+        boolean success = true;
+        try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) {
+            truffleCompiler.compileMethod(optimizedCallTarget);
+        } catch (Throwable e) {
+            optimizedCallTarget.notifyCompilationFailed(e);
+            success = false;
+        } finally {
+            optimizedCallTarget.notifyCompilationFinished(success);
+        }
+    }
+
     public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason);
 
     public abstract void waitForCompilation(OptimizedCallTarget optimizedCallTarget, long timeout) throws ExecutionException, TimeoutException;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java	Fri May 15 11:55:52 2015 +0200
@@ -28,8 +28,6 @@
 
 public final class OptimizedOSRLoopNode extends LoopNode implements ReplaceObserver {
 
-    private static final int OSR_THRESHOLD = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue();
-
     private int interpreterLoopCount;
     private OptimizedCallTarget compiledTarget;
 
@@ -75,7 +73,8 @@
     }
 
     private boolean profilingLoop(VirtualFrame frame) {
-        int overflowLoopCount = Integer.MAX_VALUE - OSR_THRESHOLD + interpreterLoopCount;
+        int osrThreshold = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue();
+        int overflowLoopCount = Integer.MAX_VALUE - osrThreshold + interpreterLoopCount;
         try {
             while (repeatableNode.executeRepeating(frame)) {
                 try {
@@ -86,7 +85,7 @@
                 }
             }
         } finally {
-            reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + OSR_THRESHOLD - interpreterLoopCount);
+            reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + osrThreshold - interpreterLoopCount);
         }
         return true;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Fri May 15 11:55:52 2015 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.truffle;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
 import java.lang.invoke.*;
@@ -71,8 +71,8 @@
     @Option(help = "New partial evaluation on Graal graphs", type = OptionType.Expert)//
     public static final StableOptionValue<Boolean> GraphPE = new StableOptionValue<>(true);
 
-    private final Providers providers;
-    private final Architecture architecture;
+    protected final Providers providers;
+    protected final Architecture architecture;
     private final CanonicalizerPhase canonicalizer;
     private final SnippetReflectionProvider snippetReflection;
     private final ResolvedJavaMethod callDirectMethod;
@@ -140,11 +140,6 @@
         }
 
         public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
-            if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) {
-                ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true));
-                builder.addPush(trueNode);
-                return true;
-            }
             return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null);
         }
     }
@@ -319,19 +314,17 @@
         }
         plugins.setInlineInvokePlugin(inlinePlugin);
         plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin());
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompiler.Optimizations, null).apply(graph);
         if (PrintTruffleExpansionHistogram.getValue()) {
             ((HistogramInlineInvokePlugin) inlinePlugin).print(callTarget, System.out);
         }
     }
 
-    protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) {
+    protected PEGraphDecoder createGraphDecoder(StructuredGraph graph) {
         GraphBuilderConfiguration newConfig = configForRoot.copy();
         InvocationPlugins parsingInvocationPlugins = newConfig.getPlugins().getInvocationPlugins();
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), parsingInvocationPlugins, true, snippetReflection);
 
-        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
-
         LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin();
 
         newConfig.setUseProfiling(false);
@@ -340,12 +333,18 @@
         plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin,
                         !PrintTruffleExpansionHistogram.getValue()));
 
-        CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
+        return new CachingPEGraphDecoder(providers, newConfig, TruffleCompiler.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
+    }
 
+    protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) {
+        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+
+        PEGraphDecoder decoder = createGraphDecoder(graph);
+
+        LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin();
         ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget);
 
-        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
-        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
+        InvocationPlugins decodingInvocationPlugins = createDecodingInvocationPlugins();
         InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements());
         if (PrintTruffleExpansionHistogram.getValue()) {
             decodingInlinePlugin = new HistogramInlineInvokePlugin(graph, decodingInlinePlugin);
@@ -358,6 +357,12 @@
         }
     }
 
+    protected InvocationPlugins createDecodingInvocationPlugins() {
+        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
+        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
+        return decodingInvocationPlugins;
+    }
+
     @SuppressWarnings("unused")
     private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
         if (GraphPE.getValue()) {
@@ -434,13 +439,13 @@
     }
 
     public StructuredGraph createRootGraph(StructuredGraph graph) {
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph);
         return graph;
     }
 
     public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
         StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null));
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph);
         return graph;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * 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.truffle;
+
+import static com.oracle.graal.api.code.CodeUtil.*;
+import static com.oracle.graal.compiler.GraalCompiler.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.Assumptions.Assumption;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.printer.*;
+import com.oracle.graal.truffle.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implementation of the Truffle compiler using Graal.
+ */
+public abstract class TruffleCompiler {
+
+    protected final Providers providers;
+    protected final Suites suites;
+    protected final GraphBuilderConfiguration config;
+    protected final LIRSuites lirSuites;
+    protected final PartialEvaluator partialEvaluator;
+    protected final Backend backend;
+    protected final GraalTruffleCompilationListener compilationNotify;
+
+    // @formatter:off
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
+        UnexpectedResultException.class,
+        SlowPathException.class,
+        ArithmeticException.class,
+        IllegalArgumentException.class,
+        VirtualMachineError.class,
+        StringIndexOutOfBoundsException.class,
+        ClassCastException.class
+    };
+    // @formatter:on
+
+    public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
+                    OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
+
+    public TruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) {
+        GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime());
+        this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
+        this.backend = backend;
+        Providers backendProviders = backend.getProviders();
+        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
+        this.providers = backendProviders.copyWith(constantReflection);
+        this.suites = suites;
+        this.lirSuites = lirSuites;
+
+        ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
+
+        GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(new Plugins(plugins))
+                        : GraphBuilderConfiguration.getDefault(new Plugins(plugins));
+        this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes).withOmitAssertions(TruffleCompilerOptions.TruffleExcludeAssertions.getValue());
+
+        this.partialEvaluator = createPartialEvaluator();
+
+        if (Debug.isEnabled()) {
+            DebugEnvironment.initialize(System.out);
+        }
+    }
+
+    protected abstract PartialEvaluator createPartialEvaluator();
+
+    public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
+        ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length];
+        for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) {
+            skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]);
+        }
+        return skippedExceptionTypes;
+    }
+
+    public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
+    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
+
+    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
+    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
+    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
+
+    public void compileMethod(final OptimizedCallTarget compilable) {
+        StructuredGraph graph = null;
+
+        compilationNotify.notifyCompilationStarted(compilable);
+
+        try {
+            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
+
+            try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) {
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
+            }
+
+            if (Thread.currentThread().isInterrupted()) {
+                return;
+            }
+
+            compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
+            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable);
+            compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
+        } catch (Throwable t) {
+            System.out.println("compilation failed!?");
+            compilationNotify.notifyCompilationFailed(compilable, graph, t);
+            throw t;
+        }
+    }
+
+    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
+        try (Scope s = Debug.scope("TruffleFinal")) {
+            Debug.dump(1, graph, "After TruffleTier");
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        CompilationResult result = null;
+        try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
+            CodeCacheProvider codeCache = providers.getCodeCache();
+            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
+            CompilationResult compilationResult = new CompilationResult(name);
+            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites,
+                            compilationResult, CompilationResultBuilderFactory.Default);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
+
+        if (graph.isInlinedMethodRecordingEnabled()) {
+            result.setMethods(graph.method(), graph.getInlinedMethods());
+        } else {
+            assert result.getMethods() == null;
+        }
+
+        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
+        Set<Assumption> newAssumptions = new HashSet<>();
+        for (Assumption assumption : graph.getAssumptions()) {
+            processAssumption(newAssumptions, assumption, validAssumptions);
+        }
+
+        if (result.getAssumptions() != null) {
+            for (Assumption assumption : result.getAssumptions()) {
+                processAssumption(newAssumptions, assumption, validAssumptions);
+            }
+        }
+
+        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
+
+        InstalledCode installedCode;
+        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
+            installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+
+        for (AssumptionValidAssumption a : validAssumptions) {
+            a.getAssumption().registerInstalledCode(installedCode);
+        }
+
+        if (Debug.isLogEnabled()) {
+            Debug.log(providers.getCodeCache().disassemble(result, installedCode));
+        }
+        return result;
+    }
+
+    protected abstract PhaseSuite<HighTierContext> createGraphBuilderSuite();
+
+    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
+        if (assumption != null) {
+            if (assumption instanceof AssumptionValidAssumption) {
+                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
+                manual.add(assumptionValidAssumption);
+            } else {
+                newAssumptions.add(assumption);
+            }
+        }
+    }
+
+    public PartialEvaluator getPartialEvaluator() {
+        return partialEvaluator;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +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.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle;
-
-import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.compiler.GraalCompiler.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CallingConvention.Type;
-import com.oracle.graal.api.meta.Assumptions.Assumption;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import com.oracle.graal.java.*;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-import com.oracle.graal.printer.*;
-import com.oracle.graal.runtime.*;
-import com.oracle.graal.truffle.nodes.*;
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Implementation of the Truffle compiler using Graal.
- */
-public class TruffleCompilerImpl {
-
-    private final Providers providers;
-    private final Suites suites;
-    private final LIRSuites lirSuites;
-    private final PartialEvaluator partialEvaluator;
-    private final Backend backend;
-    private final GraphBuilderConfiguration config;
-    private final RuntimeProvider runtime;
-    private final GraalTruffleCompilationListener compilationNotify;
-
-    // @formatter:off
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{
-        UnexpectedResultException.class,
-        SlowPathException.class,
-        ArithmeticException.class,
-        IllegalArgumentException.class,
-        VirtualMachineError.class,
-        StringIndexOutOfBoundsException.class,
-        ClassCastException.class
-    };
-    // @formatter:on
-
-    public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
-                    OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
-
-    public TruffleCompilerImpl() {
-        GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime());
-        this.runtime = Graal.getRequiredCapability(RuntimeProvider.class);
-        this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
-        this.backend = runtime.getHostBackend();
-        Providers backendProviders = backend.getProviders();
-        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
-        this.providers = backendProviders.copyWith(constantReflection);
-        this.suites = backend.getSuites().getDefaultSuites();
-        this.lirSuites = backend.getSuites().getDefaultLIRSuites();
-
-        ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
-
-        GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-        // copy all plugins from the host
-        Plugins plugins = new Plugins(phase.getGraphBuilderConfig().getPlugins());
-        GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(plugins) : GraphBuilderConfiguration.getDefault(plugins);
-        this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes);
-
-        this.partialEvaluator = new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch);
-
-        if (Debug.isEnabled()) {
-            DebugEnvironment.initialize(System.out);
-        }
-    }
-
-    public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) {
-        ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length];
-        for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) {
-            skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]);
-        }
-        return skippedExceptionTypes;
-    }
-
-    public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime");
-    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
-    public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
-
-    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
-    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
-    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
-
-    public void compileMethod(final OptimizedCallTarget compilable) {
-        StructuredGraph graph = null;
-
-        compilationNotify.notifyCompilationStarted(compilable);
-
-        try {
-            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
-
-            try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
-            }
-
-            if (Thread.currentThread().isInterrupted()) {
-                return;
-            }
-
-            compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
-            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable);
-            compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
-        } catch (Throwable t) {
-            System.out.println("compilation failed!?");
-            compilationNotify.notifyCompilationFailed(compilable, graph, t);
-            throw t;
-        }
-    }
-
-    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
-        try (Scope s = Debug.scope("TruffleFinal")) {
-            Debug.dump(1, graph, "After TruffleTier");
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        CompilationResult result = null;
-        try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) {
-            CodeCacheProvider codeCache = providers.getCodeCache();
-            CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
-            CompilationResult compilationResult = new CompilationResult(name);
-            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites,
-                            compilationResult, CompilationResultBuilderFactory.Default);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
-
-        if (graph.isInlinedMethodRecordingEnabled()) {
-            result.setMethods(graph.method(), graph.getInlinedMethods());
-        } else {
-            assert result.getMethods() == null;
-        }
-
-        List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
-        Set<Assumption> newAssumptions = new HashSet<>();
-        for (Assumption assumption : graph.getAssumptions()) {
-            processAssumption(newAssumptions, assumption, validAssumptions);
-        }
-
-        if (result.getAssumptions() != null) {
-            for (Assumption assumption : result.getAssumptions()) {
-                processAssumption(newAssumptions, assumption, validAssumptions);
-            }
-        }
-
-        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
-
-        InstalledCode installedCode;
-        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) {
-            installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        for (AssumptionValidAssumption a : validAssumptions) {
-            a.getAssumption().registerInstalledCode(installedCode);
-        }
-
-        if (Debug.isLogEnabled()) {
-            Debug.log(providers.getCodeCache().disassemble(result, installedCode));
-        }
-        return result;
-    }
-
-    private PhaseSuite<HighTierContext> createGraphBuilderSuite() {
-        PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
-        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
-        iterator.remove();
-        iterator.add(new GraphBuilderPhase(config));
-        return suite;
-    }
-
-    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
-        if (assumption != null) {
-            if (assumption instanceof AssumptionValidAssumption) {
-                AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
-                manual.add(assumptionValidAssumption);
-            } else {
-                newAssumptions.add(assumption);
-            }
-        }
-    }
-
-    public PartialEvaluator getPartialEvaluator() {
-        return partialEvaluator;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java	Fri May 15 11:55:52 2015 +0200
@@ -53,11 +53,15 @@
     }
 
     private ObjectLocationIdentity(JavaConstant object) {
-        super(false);
         this.object = object;
     }
 
     @Override
+    public boolean isImmutable() {
+        return false;
+    }
+
+    @Override
     public String toString() {
         return "Identity(" + object + ")";
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri May 15 11:55:52 2015 +0200
@@ -109,6 +109,12 @@
         return success;
     }
 
+    public static void trace(String format) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format);
+        }
+    }
+
     public static void trace(String format, Object obj) {
         if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
             Debug.logv(format, obj);
@@ -127,6 +133,12 @@
         }
     }
 
+    public static void trace(String format, Object obj, Object obj2, Object obj3, Object obj4) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2, obj3, obj4);
+        }
+    }
+
     public static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
             return matchesHelper(graph, filter);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test.instrument;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdvancedInstrumentCounterRoot;
+
+/**
+ * Tests the kind of instrumentation where a client can provide an AST fragment to be
+ * <em>spliced</em> directly into the AST.
+ */
+public class AdvancedInstrumentTest {
+
+    @Test
+    public void testAdvancedInstrumentListener() {
+        // Create a simple addition AST
+        final TruffleRuntime runtime = Truffle.getRuntime();
+        final TestValueNode leftValueNode = new TestValueNode(6);
+        final TestValueNode rightValueNode = new TestValueNode(7);
+        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
+        final TestRootNode rootNode = new TestRootNode(addNode);
+        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
+
+        // Ensure it executes correctly
+        assertEquals(13, callTarget1.call());
+
+        // Probe the addition node
+        final Probe probe = addNode.probe();
+
+        assertEquals(13, callTarget1.call());
+
+        // Attach a null factory; it never actually attaches a node.
+        final Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
+
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
+                return null;
+            }
+        }, null, "test AdvancedInstrument");
+        probe.attach(instrument);
+
+        assertEquals(13, callTarget1.call());
+
+        final TestAdvancedInstrumentCounterRoot counter = new TestAdvancedInstrumentCounterRoot();
+
+        // Attach a factory that splices an execution counter into the AST.
+        probe.attach(Instrument.create(null, new AdvancedInstrumentRootFactory() {
+
+            public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
+                return counter;
+            }
+        }, null, "test AdvancedInstrument"));
+        assertEquals(0, counter.getCount());
+
+        assertEquals(13, callTarget1.call());
+
+        assertEquals(1, counter.getCount());
+    }
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Fri May 15 11:55:52 2015 +0200
@@ -167,12 +167,12 @@
         }
     }
 
-    static class TestToolEvalCounterNode extends ToolEvalNode {
+    static class TestAdvancedInstrumentCounterRoot extends AdvancedInstrumentRoot {
 
         private long count;
 
         @Override
-        public Object executeToolEvalNode(Node node, VirtualFrame vFrame) {
+        public Object executeRoot(Node node, VirtualFrame vFrame) {
             count++;
             return null;
         }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.test.instrument;
-
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestToolEvalCounterNode;
-
-/**
- * Tests the kind of instrumentation where a client can provide an AST fragment to be
- * <em>spliced</em> directly into the AST.
- */
-public class ToolEvalInstrumentTest {
-
-    @Test
-    public void testSpliceInstrumentListener() {
-        // Create a simple addition AST
-        final TruffleRuntime runtime = Truffle.getRuntime();
-        final TestValueNode leftValueNode = new TestValueNode(6);
-        final TestValueNode rightValueNode = new TestValueNode(7);
-        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
-        final TestRootNode rootNode = new TestRootNode(addNode);
-        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
-
-        // Ensure it executes correctly
-        assertEquals(13, callTarget1.call());
-
-        // Probe the addition node
-        final Probe probe = addNode.probe();
-
-        assertEquals(13, callTarget1.call());
-
-        // Attach a null listener; it never actually attaches a node.
-        final Instrument instrument = Instrument.create(new ToolEvalNodeFactory() {
-
-            public ToolEvalNode createToolEvalNode(Probe p, Node n) {
-                return null;
-            }
-        }, null);
-        probe.attach(instrument);
-
-        assertEquals(13, callTarget1.call());
-
-        final TestToolEvalCounterNode counter = new TestToolEvalCounterNode();
-
-        // Attach a listener that splices an execution counter into the AST.
-        probe.attach(Instrument.create(new ToolEvalNodeFactory() {
-
-            public ToolEvalNode createToolEvalNode(Probe p, Node n) {
-                return counter;
-            }
-        }, null));
-        assertEquals(0, counter.getCount());
-
-        assertEquals(13, callTarget1.call());
-
-        assertEquals(1, counter.getCount());
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Listener for receiving the result a client-provided {@linkplain AdvancedInstrumentRoot AST
+ * fragment}, when executed by a
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRoot
+ * @see AdvancedInstrumentRootFactory
+ */
+public interface AdvancedInstrumentResultListener {
+
+    /**
+     * Notifies listener that a client-provided {@linkplain AdvancedInstrumentRoot AST fragment} has
+     * been executed by an
+     * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+     * Advanced Instrument} with the specified result, possibly {@code null}.
+     * <p>
+     * <strong>Note: </strong> Truffle will attempt to optimize implementations through partial
+     * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted.
+     *
+     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
+     *            attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @param result the result of this AST fragment's execution
+     */
+    void notifyResult(Node node, VirtualFrame vFrame, Object result);
+
+    /**
+     * Notifies listener that execution of client-provided {@linkplain AdvancedInstrumentRoot AST
+     * fragment} filed during execution by a @linkplain
+     * Instrument#create(AdvancedInstrumentRootFactory, String) Advanced Instrument}.
+     * <p>
+     * <strong>Note: </strong> Truffle will attempt to optimize implementations through partial
+     * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted.
+     *
+     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
+     *            attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @param ex the exception
+     */
+    void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle
+ * optimization, by an
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRootFactory
+ * @see AdvancedInstrumentResultListener
+ */
+public abstract class AdvancedInstrumentRoot extends Node implements InstrumentationNode {
+
+    /**
+     * Executes this AST fragment on behalf of a client {@link Instrument}, just before the
+     * guest-language AST node to which the {@link Probe} holding the Instrument is executed.
+     *
+     * @param node the guest-language AST node to which the host Instrument's Probe is attached
+     * @param vFrame execution frame at the guest-language AST node
+     * @return the result of this AST fragment's execution
+     */
+    public abstract Object executeRoot(Node node, VirtualFrame vFrame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java	Fri May 15 11:55:52 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Creator of {@linkplain AdvancedInstrumentRoot AST fragments} suitable for efficient execution,
+ * subject to full Truffle optimization, by an
+ * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+ * Advanced Instrument}.
+ *
+ * @see Instrument
+ * @see AdvancedInstrumentRoot
+ */
+public interface AdvancedInstrumentRootFactory {
+
+    /**
+     * Provider of {@linkplain AdvancedInstrumentRoot AST fragment} instances for efficient
+     * execution via instrumentation, subject to full Truffle optimization, at a {@linkplain Probe
+     * Probed} site in a guest-language AST.
+     *
+     * @param probe the Probe to which the Instrument requesting the AST fragment is attached
+     * @param node the guest-language AST location that is the context in which the requesting
+     *            Instrument must execute the AST fragment.
+     * @return a newly created AST fragment suitable for execution, via instrumentation, in the
+     *         execution context of the specified guest-language AST site.
+     */
+    AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node);
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 15 11:40:02 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri May 15 11:55:52 2015 +0200
@@ -127,16 +127,19 @@
     }
 
     /**
-     * Creates a <em>Tool Eval Instrument</em>: this Instrument executes efficiently, subject to
+     * Creates an <em>Advanced Instrument</em>: this Instrument executes efficiently, subject to
      * full Truffle optimization, a client-provided AST fragment every time the Probed node is
      * entered.
      *
-     * @param toolEvalNodeFactory provider of AST fragments on behalf of the client
+     * @param resultListener optional client callback for results/failure notification
+     * @param rootFactory provider of AST fragments on behalf of the client
+     * @param requiredResultType optional requirement, any non-assignable result is reported to the
+     *            the listener, if any, as a failure
      * @param instrumentInfo optional description of the instrument's role, intended for debugging.
      * @return a new instrument, ready for attachment at a probe
      */
-    public static Instrument create(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) {
-        return new ToolEvalInstrument(toolEvalNodeFactory, instrumentInfo);
+    public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
+        return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo);
     }
 
     // TODO (mlvdv) experimental
@@ -379,22 +382,22 @@
      * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle
      * AST with potential for full optimization.
      */
-    private static final class ToolEvalInstrument extends Instrument {
+    private static final class AdvancedInstrument extends Instrument {
+
+        private final AdvancedInstrumentResultListener resultListener;
+        private final AdvancedInstrumentRootFactory rootFactory;
+        private final Class<?> requiredResultType;
 
-        /**
-         * Client-provided supplier of new node instances to attach.
-         */
-        private final ToolEvalNodeFactory toolEvalNodeFactory;
-
-        private ToolEvalInstrument(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) {
+        private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
             super(instrumentInfo);
-            this.toolEvalNodeFactory = toolEvalNodeFactory;
-
+            this.resultListener = resultListener;
+            this.rootFactory = rootFactory;
+            this.requiredResultType = requiredResultType;
         }
 
         @Override
         AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new ToolEvalNodeInstrumentNode(nextNode);
+            return new AdvancedInstrumentNode(nextNode);
         }
 
         @Override
@@ -406,7 +409,7 @@
                     return instrumentNode.nextInstrumentNode;
                 }
                 // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(ToolEvalInstrument.this);
+                found = instrumentNode.removeFromChain(AdvancedInstrument.this);
             }
             if (!found) {
                 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
@@ -415,35 +418,62 @@
         }
 
         /**
-         * Node that implements a {@link ToolEvalInstrument} in a particular AST.
+         * Node that implements a {@link AdvancedInstrument} in a particular AST.
          */
         @NodeInfo(cost = NodeCost.NONE)
-        private final class ToolEvalNodeInstrumentNode extends AbstractInstrumentNode {
+        private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
 
-            @Child private ToolEvalNode toolEvalNode;
+            @Child private AdvancedInstrumentRoot instrumentRoot;
 
-            private ToolEvalNodeInstrumentNode(AbstractInstrumentNode nextNode) {
+            private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
                 super(nextNode);
             }
 
             public void enter(Node node, VirtualFrame vFrame) {
-                if (toolEvalNode == null) {
-                    final ToolEvalNode newToolEvalNodeNode = ToolEvalInstrument.this.toolEvalNodeFactory.createToolEvalNode(ToolEvalInstrument.this.probe, node);
-                    if (newToolEvalNodeNode != null) {
-                        toolEvalNode = newToolEvalNodeNode;
-                        adoptChildren();
-                        ToolEvalInstrument.this.probe.invalidateProbeUnchanged();
+                if (instrumentRoot == null) {
+                    try {
+                        final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
+                        if (newInstrumentRoot != null) {
+                            instrumentRoot = newInstrumentRoot;
+                            adoptChildren();
+                            AdvancedInstrument.this.probe.invalidateProbeUnchanged();
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.notifyFailure(node, vFrame, ex);
+                        }
                     }
                 }
-                if (toolEvalNode != null) {
-                    // TODO (mlvdv) should report exception ; non-trivial architectural change
-                    toolEvalNode.executeToolEvalNode(node, vFrame);
+                if (instrumentRoot != null) {
+                    try {
+                        final Object result = instrumentRoot.executeRoot(node, vFrame);
+                        if (resultListener != null) {
+                            checkResultType(result);
+                            resultListener.notifyResult(node, vFrame, result);
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.notifyFailure(node, vFrame, ex);
+                        }
+                    }
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.enter(node, vFrame);
                 }
             }
 
+            private void checkResultType(Object result) {
+                if (requiredResultType == null) {
+                    return;
+                }
+                if (result == null) {
+                    throw new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
+                }
+                if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
+                    throw new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
+                }
+            }
+
             public void returnVoid(Node node, VirtualFrame vFrame) {
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnVoid(node, vFrame);
@@ -464,7 +494,7 @@
 
             public String instrumentationInfo() {
                 final String info = getInstrumentInfo();
-                return info != null ? info : toolEvalNodeFactory.getClass().getSimpleName();
+                return info != null ? info : rootFactory.getClass().getSimpleName();
             }
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle
- * optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval
- * Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNodeFactory
- * @see ToolEvalResultListener
- */
-public abstract class ToolEvalNode extends Node implements InstrumentationNode {
-
-    /**
-     * Executes this AST fragment on behalf of a client {@link Instrument}, just before the
-     * guest-language AST node to which the {@link Probe} holding the Instrument is executed.
-     *
-     * @param node the guest-language AST node to which the host Instrument's Probe is attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @return the result of this AST fragment's execution
-     */
-    public abstract Object executeToolEvalNode(Node node, VirtualFrame vFrame);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Creator of {@linkplain ToolEvalNode AST fragments} suitable for efficient execution, subject to
- * full Truffle optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool
- * Eval Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNode
- */
-public interface ToolEvalNodeFactory {
-
-    /**
-     * Provider of {@linkplain ToolEvalNode AST fragment} instances for efficient execution via
-     * instrumentation, subject to full Truffle optimization, at a {@linkplain Probe Probed} site in
-     * a guest-language AST.
-     *
-     * @param probe the Probe to which the Instrument requesting the AST fragment is attached
-     * @param node the guest-language AST location that is the context in which the requesting
-     *            Instrument must execute the AST fragment.
-     * @return a newly created AST fragment suitable for execution, via instrumentation, in the
-     *         execution context of the specified guest-language AST site.
-     */
-    ToolEvalNode createToolEvalNode(Probe probe, Node node);
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java	Fri May 15 11:40:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Listener for receiving the result a client-provided {@linkplain ToolEvalNode AST fragment}, when
- * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval Instrument}.
- *
- * @see Instrument
- * @see ToolEvalNode
- * @see ToolEvalNodeFactory
- */
-public interface ToolEvalResultListener {
-
-    /**
-     * Notifies listener that a client-provided {@linkplain ToolEvalNode AST fragment} has been
-     * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval
-     * Instrument} with the specified result, possibly {@code null}.
-     *
-     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
-     *            attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @param result the result of this AST fragment's execution
-     */
-    void notifyToolEvalResult(Node node, VirtualFrame vFrame, Object result);
-
-    /**
-     * Notifies listener that execution of client-provided {@linkplain ToolEvalNode AST fragment}
-     * filed during execution by a @linkplain Instrument#create(ToolEvalNodeFactory, String) Tool
-     * Eval Instrument}.
-     *
-     * @param node the guest-language AST node to which the host Instrument's {@link Probe} is
-     *            attached
-     * @param vFrame execution frame at the guest-language AST node
-     * @param ex the exception
-     */
-    void notifyToolEvalFailure(Node node, VirtualFrame vFrame, RuntimeException ex);
-
-}
--- a/mxtool/mx.py	Fri May 15 11:40:02 2015 +0200
+++ b/mxtool/mx.py	Fri May 15 11:55:52 2015 +0200
@@ -622,7 +622,7 @@
 
         if not exists(cachePath) or sha1OfFile(cachePath) != sha1:
             if exists(cachePath):
-                log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - re-downloading')
+                log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - found ' + sha1OfFile(cachePath) + ' - re-downloading')
             print 'Downloading ' + ("sources " if sources else "") + name + ' from ' + str(urls)
             download(cachePath, urls)
 
@@ -1019,6 +1019,7 @@
             p = Project(self, name, srcDirs, deps, javaCompliance, workingSets, d)
             p.checkstyleProj = attrs.pop('checkstyle', name)
             p.native = attrs.pop('native', '') == 'true'
+            p.checkPackagePrefix = attrs.pop('checkPackagePrefix', 'true') == 'true'
             if not p.native and p.javaCompliance is None:
                 abort('javaCompliance property required for non-native project ' + name)
             if len(ap) > 0:
@@ -3355,9 +3356,10 @@
     nonCanonical = []
     for s in suites(True):
         for p in s.projects:
-            for pkg in p.defined_java_packages():
-                if not pkg.startswith(p.name):
-                    abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
+            if p.checkPackagePrefix:
+                for pkg in p.defined_java_packages():
+                    if not pkg.startswith(p.name):
+                        abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg))
 
             ignoredDeps = set([name for name in p.deps if project(name, False) is not None])
             for pkg in p.imported_java_packages():
@@ -3451,7 +3453,7 @@
 
         config = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
         if not exists(config):
-            logv('[No Checkstyle configuration foudn for {0} - skipping]'.format(p))
+            logv('[No Checkstyle configuration found for {0} - skipping]'.format(p))
             continue
 
         # skip checking this Java project if its Java compliance level is "higher" than the configured JDK