changeset 23260:206bf428d745

Merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 05 Jan 2016 16:42:05 -0800
parents 47e45579e9ce (current diff) 61e5bc24179e (diff)
children 2ea1d1979187 c95a2eaf97e1
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctFilteredNodeIterable.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java
diffstat 271 files changed, 16551 insertions(+), 1924 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Jan 05 16:32:42 2016 -0800
+++ b/.hgtags	Tue Jan 05 16:42:05 2016 -0800
@@ -620,3 +620,4 @@
 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8
 3e8357b49024cb168ab5ebd511d8b5c03c068f75 graal-0.9
 795ada9208d8f35991b98bb934f624c70b8a0183 graal-0.10
+2643ba182e6f704aab7222d49f72456411e60c7b graal-0.11
--- a/CHANGELOG.md	Tue Jan 05 16:32:42 2016 -0800
+++ b/CHANGELOG.md	Tue Jan 05 16:42:05 2016 -0800
@@ -5,6 +5,16 @@
 ## `tip`
 ...
 
+## Version 0.11
+23-Dec-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.11)
+* Moved support for command line options from JVMCI to Graal.
+* Made invocation plugin initialization lazy: plugins for a class are initialized first time compiler parses a method in the class.
+* Removed method handle special case logic for 8u60 and later.
+* Generate graph builder plugins for @NodeIntrinsic and @Fold methods instead of using reflection.
+* Converted LoadHubNode into normal FloatingNode from FloatingGuardedNode.
+* Enabled CRC32 intrinsics on SPARC.
+* Added log methods to Debug with 9 and 10 arguments.
+
 ## Version 0.10
 17-Nov-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.10)
 * Added experimental Trace Register Allocator.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64.test/src/com/oracle/graal/asm/aarch64/test/AArch64MacroAssemblerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,284 @@
+/*
+ * 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.asm.aarch64.test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.util.EnumSet;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan;
+import com.oracle.graal.test.GraalTest;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64.CPUFeature;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+public class AArch64MacroAssemblerTest extends GraalTest {
+
+    private AArch64MacroAssembler masm;
+    private TestProtectedAssembler asm;
+    private Register base;
+    private Register index;
+    private Register scratch;
+
+    private static EnumSet<AArch64.CPUFeature> computeFeatures() {
+        EnumSet<AArch64.CPUFeature> features = EnumSet.noneOf(AArch64.CPUFeature.class);
+        features.add(CPUFeature.FP);
+        return features;
+    }
+
+    private static EnumSet<AArch64.Flag> computeFlags() {
+        EnumSet<AArch64.Flag> flags = EnumSet.noneOf(AArch64.Flag.class);
+        return flags;
+    }
+
+    private static TargetDescription createTarget() {
+        final int stackFrameAlignment = 16;
+        final int implicitNullCheckLimit = 4096;
+        final boolean inlineObjects = true;
+        Architecture arch = new AArch64(computeFeatures(), computeFlags());
+        return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
+    }
+
+    @Before
+    public void setupEnvironment() {
+        TargetDescription target = createTarget();
+        masm = new AArch64MacroAssembler(target);
+        asm = new TestProtectedAssembler(target);
+        base = AArch64.r10;
+        index = AArch64.r13;
+        scratch = AArch64.r15;
+    }
+
+    @Test
+    public void testGenerateAddressPlan() {
+        AddressGenerationPlan plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(8), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch &&
+                        (plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED || plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED));
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(8) - 1, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_UNSCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 1);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 2, false, 4);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.IMMEDIATE_SCALED);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(0, false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.NO_WORK && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(9), false, 0);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-NumUtil.getNbitNumberInt(12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(-(NumUtil.getNbitNumberInt(12) << 12), false, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12), true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_BASE && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(12) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && !plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+
+        plan = AArch64MacroAssembler.generateAddressPlan(NumUtil.getNbitNumberInt(13) << 3, true, 8);
+        Assert.assertTrue(plan.workPlan == AddressGenerationPlan.WorkPlan.ADD_TO_INDEX && plan.needsScratch && plan.addressingMode == AArch64Address.AddressingMode.REGISTER_OFFSET);
+    }
+
+    @Test
+    public void testMakeAddressNoAction() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12) << 3, AArch64.zr, false, 8, null, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.IMMEDIATE_SCALED && address.getBase().equals(base) &&
+                        address.getOffset().equals(AArch64.zr) && address.getImmediateRaw() == NumUtil.getNbitNumberInt(12));
+        // No code generated.
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndex() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(scratch));
+        asm.add(64, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBaseNoOverwrite() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(scratch) && address.getOffset().equals(index));
+        asm.add(64, scratch, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddBase() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(12), index, false, 8, null, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.REGISTER_OFFSET && address.getBase().equals(base) && address.getOffset().equals(index));
+        asm.add(64, base, base, NumUtil.getNbitNumberInt(12));
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexNoOverwriteExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, false);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(scratch) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, scratch, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testMakeAddressAddIndexExtend() {
+        AArch64Address address = masm.makeAddress(base, NumUtil.getNbitNumberInt(8) << 5, index, true, 8, scratch, true);
+        Assert.assertTrue(address.isScaled() && address.getAddressingMode() == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET && address.getBase().equals(base) &&
+                        address.getOffset().equals(index) && address.getExtendType() == AArch64Assembler.ExtendType.SXTW);
+        asm.add(32, index, index, NumUtil.getNbitNumberInt(8) << 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressUnscaled2() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createUnscaledImmediateAddress(base, -NumUtil.getNbitNumberInt(8));
+        masm.loadAddress(dst, address, 8);
+        asm.sub(64, dst, base, NumUtil.getNbitNumberInt(8));
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(12));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(9) << 3);
+        asm.add(64, dst, dst, NumUtil.getNbitNumberInt(3) << 12);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledLowerOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, NumUtil.getNbitNumberInt(5));
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, NumUtil.getNbitNumberInt(5) << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressScaledHigherOnly() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createScaledImmediateAddress(base, 1 << 11);
+        masm.loadAddress(dst, address, 8);
+        asm.add(64, dst, base, 1 << 11 << 3);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, false);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createRegisterOffsetAddress(base, index, true);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ShiftType.LSL, 2);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetUnscaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, false, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 0);
+        compareAssembly();
+    }
+
+    @Test
+    public void testLoadAddressExtendedRegisterOffsetScaled() {
+        Register dst = AArch64.r26;
+        AArch64Address address = AArch64Address.createExtendedRegisterOffsetAddress(base, index, true, AArch64Assembler.ExtendType.SXTW);
+        masm.loadAddress(dst, address, 4);
+        asm.add(64, dst, base, index, AArch64Assembler.ExtendType.SXTW, 2);
+        compareAssembly();
+    }
+
+    /**
+     * Compares assembly generated by the macro assembler to the hand-generated assembly.
+     */
+    private void compareAssembly() {
+        byte[] expected = asm.close(true);
+        byte[] actual = masm.close(true);
+        assertArrayEquals(expected, actual);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64.test/src/com/oracle/graal/asm/aarch64/test/TestProtectedAssembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,550 @@
+/*
+ * 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.asm.aarch64.test;
+
+import com.oracle.graal.asm.AbstractAddress;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+
+/**
+ * Cheat so that we can test protected functions of assembler.
+ */
+class TestProtectedAssembler extends AArch64Assembler {
+
+    public TestProtectedAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        super.cbnz(size, reg, imm21, pos);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        super.cbz(size, reg, imm21, pos);
+    }
+
+    @Override
+    public void ands(int size, Register dst, Register src, long bimm) {
+        super.ands(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21) {
+        super.b(condition, imm21);
+    }
+
+    @Override
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        super.b(condition, imm21, pos);
+    }
+
+    @Override
+    protected void cbnz(int size, Register reg, int imm21) {
+        super.cbnz(size, reg, imm21);
+    }
+
+    @Override
+    protected void cbz(int size, Register reg, int imm21) {
+        super.cbz(size, reg, imm21);
+    }
+
+    @Override
+    protected void b(int imm28) {
+        super.b(imm28);
+    }
+
+    @Override
+    protected void b(int imm28, int pos) {
+        super.b(imm28, pos);
+    }
+
+    @Override
+    public void bl(int imm28) {
+        super.bl(imm28);
+    }
+
+    @Override
+    public void blr(Register reg) {
+        super.blr(reg);
+    }
+
+    @Override
+    protected void br(Register reg) {
+        super.br(reg);
+    }
+
+    @Override
+    public void ret(Register reg) {
+        super.ret(reg);
+    }
+
+    @Override
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        super.ldr(srcSize, rt, address);
+    }
+
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        super.ldrs(targetSize, srcSize, rt, address);
+    }
+
+    @Override
+    public void str(int destSize, Register rt, AArch64Address address) {
+        super.str(destSize, rt, address);
+    }
+
+    @Override
+    protected void ldxr(int size, Register rt, AArch64Address address) {
+        super.ldxr(size, rt, address);
+    }
+
+    @Override
+    protected void stxr(int size, Register rs, Register rt, AArch64Address address) {
+        super.stxr(size, rs, rt, address);
+    }
+
+    @Override
+    protected void ldar(int size, Register rt, AArch64Address address) {
+        super.ldar(size, rt, address);
+    }
+
+    @Override
+    protected void stlr(int size, Register rt, AArch64Address address) {
+        super.stlr(size, rt, address);
+    }
+
+    @Override
+    public void ldaxr(int size, Register rt, AArch64Address address) {
+        super.ldaxr(size, rt, address);
+    }
+
+    @Override
+    public void stlxr(int size, Register rs, Register rt, AArch64Address address) {
+        super.stlxr(size, rs, rt, address);
+    }
+
+    @Override
+    public void adr(Register dst, int imm21) {
+        super.adr(dst, imm21);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src, int aimm) {
+        super.add(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        super.adds(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        super.sub(size, dst, src, aimm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        super.subs(size, dst, src, aimm);
+    }
+
+    @Override
+    public void and(int size, Register dst, Register src, long bimm) {
+        super.and(size, dst, src, bimm);
+    }
+
+    @Override
+    public void eor(int size, Register dst, Register src, long bimm) {
+        super.eor(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    @Override
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movz(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        super.movn(size, dst, uimm16, shiftAmt);
+    }
+
+    @Override
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        super.movk(size, dst, uimm16, pos);
+    }
+
+    @Override
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        super.bfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        super.ubfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        super.sbfm(size, dst, src, r, s);
+    }
+
+    @Override
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        super.extr(size, dst, src1, src2, lsb);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.adds(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.subs(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.add(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        super.sub(size, dst, src1, src2, shiftType, imm);
+    }
+
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.add(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.adds(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.sub(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        super.subs(size, dst, src1, src2, extendType, shiftAmt);
+    }
+
+    @Override
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.and(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.ands(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bic(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.bics(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eon(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.eor(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orr(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        super.orn(size, dst, src1, src2, shiftType, shiftAmt);
+    }
+
+    @Override
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        super.asr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        super.lsl(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        super.lsr(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        super.ror(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void cls(int size, Register dst, Register src) {
+        super.cls(size, dst, src);
+    }
+
+    @Override
+    public void clz(int size, Register dst, Register src) {
+        super.clz(size, dst, src);
+    }
+
+    @Override
+    protected void rbit(int size, Register dst, Register src) {
+        super.rbit(size, dst, src);
+    }
+
+    @Override
+    public void rev(int size, Register dst, Register src) {
+        super.rev(size, dst, src);
+    }
+
+    @Override
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csneg(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.csinc(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.madd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.msub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        super.sdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        super.udiv(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fldr(int size, Register rt, AArch64Address address) {
+        super.fldr(size, rt, address);
+    }
+
+    @Override
+    public void fstr(int size, Register rt, AArch64Address address) {
+        super.fstr(size, rt, address);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, Register src) {
+        super.fmov(size, dst, src);
+    }
+
+    @Override
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        super.fmovFpu2Cpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        super.fmovCpu2Fpu(size, dst, src);
+    }
+
+    @Override
+    protected void fmov(int size, Register dst, double imm) {
+        super.fmov(size, dst, imm);
+    }
+
+    @Override
+    public void fcvt(int srcSize, Register dst, Register src) {
+        super.fcvt(srcSize, dst, src);
+    }
+
+    @Override
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        super.fcvtzs(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        super.scvtf(targetSize, srcSize, dst, src);
+    }
+
+    @Override
+    protected void frintz(int size, Register dst, Register src) {
+        super.frintz(size, dst, src);
+    }
+
+    @Override
+    public void fabs(int size, Register dst, Register src) {
+        super.fabs(size, dst, src);
+    }
+
+    @Override
+    public void fneg(int size, Register dst, Register src) {
+        super.fneg(size, dst, src);
+    }
+
+    @Override
+    public void fsqrt(int size, Register dst, Register src) {
+        super.fsqrt(size, dst, src);
+    }
+
+    @Override
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        super.fadd(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        super.fsub(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        super.fmul(size, dst, src1, src2);
+    }
+
+    @Override
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        super.fdiv(size, dst, src1, src2);
+    }
+
+    @Override
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmadd(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        super.fmsub(size, dst, src1, src2, src3);
+    }
+
+    @Override
+    public void fcmp(int size, Register src1, Register src2) {
+        super.fcmp(size, src1, src2);
+    }
+
+    @Override
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        super.fccmp(size, src1, src2, uimm4, condition);
+    }
+
+    @Override
+    public void fcmpZero(int size, Register src) {
+        super.fcmpZero(size, src);
+    }
+
+    @Override
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        super.fcsel(size, dst, src1, src2, condition);
+    }
+
+    @Override
+    protected void hlt(int uimm16) {
+        super.hlt(uimm16);
+    }
+
+    @Override
+    protected void brk(int uimm16) {
+        super.brk(uimm16);
+    }
+
+    @Override
+    protected void hint(SystemHint hint) {
+        super.hint(hint);
+    }
+
+    @Override
+    protected void clrex() {
+        super.clrex();
+    }
+
+    @Override
+    public void dmb(BarrierKind barrierKind) {
+        super.dmb(barrierKind);
+    }
+
+    @Override
+    public void align(int modulus) {
+    }
+
+    @Override
+    public void jmp(Label l) {
+    }
+
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+
+    }
+
+    @Override
+    public AbstractAddress makeAddress(Register base, int displacement) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void ensureUniquePC() {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64Address.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.AbstractAddress;
+
+import jdk.vm.ci.common.JVMCIError;
+
+/**
+ * Represents an address in target machine memory, specified using one of the different addressing
+ * modes of the AArch64 ISA. - Base register only - Base register + immediate or register with
+ * shifted offset - Pre-indexed: base + immediate offset are written back to base register, value
+ * used in instruction is base + offset - Post-indexed: base + offset (immediate or register) are
+ * written back to base register, value used in instruction is base only - Literal: PC + 19-bit
+ * signed word aligned offset
+ * <p>
+ * Not all addressing modes are supported for all instructions.
+ */
+public final class AArch64Address extends AbstractAddress {
+    // Placeholder for addresses that get patched later.
+    public static final AArch64Address PLACEHOLDER = createPcLiteralAddress(0);
+
+    public enum AddressingMode {
+        /**
+         * base + uimm12 << log2(memory_transfer_size).
+         */
+        IMMEDIATE_SCALED,
+        /**
+         * base + imm9.
+         */
+        IMMEDIATE_UNSCALED,
+        /**
+         * base.
+         */
+        BASE_REGISTER_ONLY,
+        /**
+         * base + offset [<< log2(memory_transfer_size)].
+         */
+        REGISTER_OFFSET,
+        /**
+         * base + extend(offset) [<< log2(memory_transfer_size)].
+         */
+        EXTENDED_REGISTER_OFFSET,
+        /**
+         * PC + imm21 (word aligned).
+         */
+        PC_LITERAL,
+        /**
+         * address = base. base is updated to base + imm9
+         */
+        IMMEDIATE_POST_INDEXED,
+        /**
+         * address = base + imm9. base is updated to base + imm9
+         */
+        IMMEDIATE_PRE_INDEXED,
+        AddressingMode,
+    }
+
+    private final Register base;
+    private final Register offset;
+    private final int immediate;
+    /**
+     * Should register offset be scaled or not.
+     */
+    private final boolean scaled;
+    private final AArch64Assembler.ExtendType extendType;
+    private final AddressingMode addressingMode;
+
+    /**
+     * General address generation mechanism. Accepted values for all parameters depend on the
+     * addressingMode. Null is never accepted for a register, if an addressMode doesn't use a
+     * register the register has to be the zero-register. extendType has to be null for every
+     * addressingMode except EXTENDED_REGISTER_OFFSET.
+     */
+    public static AArch64Address createAddress(AddressingMode addressingMode, Register base, Register offset, int immediate, boolean isScaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, immediate, isScaled, extendType, addressingMode);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying a post-indexed immediate address pointing to base. After
+     *         ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPostIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_POST_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying a pre-indexed immediate address pointing to base + imm9.
+     *         After ldr/str instruction, base is updated to point to base + imm9
+     */
+    public static AArch64Address createPreIndexedImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_PRE_INDEXED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm12 Unsigned 12 bit immediate value. This is scaled by the word access size. This
+     *            means if this address is used to load/store a word, the immediate is shifted by 2
+     *            (log2Ceil(4)).
+     * @return AArch64Address specifying a signed address of the form base + imm12 <<
+     *         log2(memory_transfer_size).
+     */
+    public static AArch64Address createScaledImmediateAddress(Register base, int imm12) {
+        return new AArch64Address(base, zr, imm12, true, null, AddressingMode.IMMEDIATE_SCALED);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param imm9 Signed 9 bit immediate value.
+     * @return AArch64Address specifying an unscaled immediate address of the form base + imm9
+     */
+    public static AArch64Address createUnscaledImmediateAddress(Register base, int imm9) {
+        return new AArch64Address(base, zr, imm9, false, null, AddressingMode.IMMEDIATE_UNSCALED);
+    }
+
+    /**
+     * @param base May not be null or the zero register.
+     * @return AArch64Address specifying the address pointed to by base.
+     */
+    public static AArch64Address createBaseRegisterOnlyAddress(Register base) {
+        return createRegisterOffsetAddress(base, zr, false);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Register specifying some offset, optionally scaled by the memory_transfer_size.
+     *            May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @return AArch64Address specifying a register offset address of the form base + offset [<<
+     *         log2 (memory_transfer_size)]
+     */
+    public static AArch64Address createRegisterOffsetAddress(Register base, Register offset, boolean scaled) {
+        return new AArch64Address(base, offset, 0, scaled, null, AddressingMode.REGISTER_OFFSET);
+    }
+
+    /**
+     * @param base may not be null or the zero-register.
+     * @param offset Word register specifying some offset, optionally scaled by the
+     *            memory_transfer_size. May not be null or the stackpointer.
+     * @param scaled Specifies whether offset should be scaled by memory_transfer_size or not.
+     * @param extendType Describes whether register is zero- or sign-extended. May not be null.
+     * @return AArch64Address specifying an extended register offset of the form base +
+     *         extendType(offset) [<< log2(memory_transfer_size)]
+     */
+    public static AArch64Address createExtendedRegisterOffsetAddress(Register base, Register offset, boolean scaled, AArch64Assembler.ExtendType extendType) {
+        return new AArch64Address(base, offset, 0, scaled, extendType, AddressingMode.EXTENDED_REGISTER_OFFSET);
+    }
+
+    /**
+     * @param imm21 Signed 21-bit offset, word aligned.
+     * @return AArch64Address specifying a PC-literal address of the form PC + offset
+     */
+    public static AArch64Address createPcLiteralAddress(int imm21) {
+        return new AArch64Address(zr, zr, imm21, false, null, AddressingMode.PC_LITERAL);
+    }
+
+    private AArch64Address(Register base, Register offset, int immediate, boolean scaled, AArch64Assembler.ExtendType extendType, AddressingMode addressingMode) {
+        this.base = base;
+        this.offset = offset;
+        if ((addressingMode == AddressingMode.REGISTER_OFFSET || addressingMode == AddressingMode.EXTENDED_REGISTER_OFFSET) && offset.equals(zr)) {
+            this.addressingMode = AddressingMode.BASE_REGISTER_ONLY;
+        } else {
+            this.addressingMode = addressingMode;
+        }
+        this.immediate = immediate;
+        this.scaled = scaled;
+        this.extendType = extendType;
+        assert verify();
+    }
+
+    private boolean verify() {
+        assert addressingMode != null;
+        assert base.getRegisterCategory().equals(AArch64.CPU) && offset.getRegisterCategory().equals(AArch64.CPU);
+
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isUnsignedNbit(12, immediate);
+            case IMMEDIATE_UNSCALED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(9, immediate);
+            case BASE_REGISTER_ONLY:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && immediate == 0;
+            case REGISTER_OFFSET:
+                return !base.equals(zr) && offset.getRegisterCategory().equals(AArch64.CPU) && extendType == null && immediate == 0;
+            case EXTENDED_REGISTER_OFFSET:
+                return !base.equals(zr) && offset.getRegisterCategory().equals(AArch64.CPU) && (extendType == AArch64Assembler.ExtendType.SXTW || extendType == AArch64Assembler.ExtendType.UXTW) &&
+                                immediate == 0;
+            case PC_LITERAL:
+                return base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(21, immediate) && ((immediate & 0x3) == 0);
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                return !base.equals(zr) && offset.equals(zr) && extendType == null && NumUtil.isSignedNbit(9, immediate);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public Register getBase() {
+        return base;
+    }
+
+    public Register getOffset() {
+        return offset;
+    }
+
+    /**
+     * @return immediate in correct representation for the given addressing mode. For example in
+     *         case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
+     *         as the 9bit signed representation.
+     */
+    public int getImmediate() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+                // 9-bit signed value
+                return immediate & NumUtil.getNbitNumberInt(9);
+            case IMMEDIATE_SCALED:
+                // Unsigned value can be returned as-is.
+                return immediate;
+            case PC_LITERAL:
+                // 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
+                return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
+            default:
+                throw JVMCIError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    /**
+     * @return Raw immediate as a 32-bit signed value.
+     */
+    public int getImmediateRaw() {
+        switch (addressingMode) {
+            case IMMEDIATE_UNSCALED:
+            case IMMEDIATE_SCALED:
+            case IMMEDIATE_POST_INDEXED:
+            case IMMEDIATE_PRE_INDEXED:
+            case PC_LITERAL:
+                return immediate;
+            default:
+                throw JVMCIError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
+        }
+    }
+
+    public boolean isScaled() {
+        return scaled;
+    }
+
+    public AArch64Assembler.ExtendType getExtendType() {
+        return extendType;
+    }
+
+    public AddressingMode getAddressingMode() {
+        return addressingMode;
+    }
+
+    public String toString(int log2TransferSize) {
+        int shiftVal = scaled ? log2TransferSize : 0;
+        switch (addressingMode) {
+            case IMMEDIATE_SCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate << log2TransferSize);
+            case IMMEDIATE_UNSCALED:
+                return String.format("[X%d, %d]", base.encoding, immediate);
+            case BASE_REGISTER_ONLY:
+                return String.format("[X%d]", base.encoding);
+            case EXTENDED_REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, W%d, %s %d]", base.encoding, offset.encoding, extendType.name(), shiftVal);
+                } else {
+                    return String.format("[X%d, W%d, %s]", base.encoding, offset.encoding, extendType.name());
+                }
+            case REGISTER_OFFSET:
+                if (shiftVal != 0) {
+                    return String.format("[X%d, X%d, LSL %d]", base.encoding, offset.encoding, shiftVal);
+                } else {
+                    // LSL 0 may be optional, but still encoded differently so we always leave it
+                    // off
+                    return String.format("[X%d, X%d]", base.encoding, offset.encoding);
+                }
+            case PC_LITERAL:
+                return String.format(".%s%d", immediate >= 0 ? "+" : "", immediate);
+            case IMMEDIATE_POST_INDEXED:
+                return String.format("[X%d],%d", base.encoding, immediate);
+            case IMMEDIATE_PRE_INDEXED:
+                return String.format("[X%d,%d]!", base.encoding, immediate);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64Assembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,2490 @@
+/*
+ * 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.asm.aarch64;
+
+import static com.oracle.graal.asm.aarch64.AArch64Assembler.InstructionType.floatFromSize;
+import static com.oracle.graal.asm.aarch64.AArch64Assembler.InstructionType.generalFromSize;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.SIMD;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import java.util.Arrays;
+
+import com.oracle.graal.asm.Assembler;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaKind;
+
+public abstract class AArch64Assembler extends Assembler {
+
+    public static class LogicalImmediateTable {
+
+        private static final Immediate[] IMMEDIATE_TABLE = buildImmediateTable();
+
+        private static final int ImmediateOffset = 10;
+        private static final int ImmediateRotateOffset = 16;
+        private static final int ImmediateSizeOffset = 22;
+
+        /**
+         * Specifies whether immediate can be represented in all cases (YES), as a 64bit instruction
+         * (SIXTY_FOUR_BIT_ONLY) or not at all (NO).
+         */
+        static enum Representable {
+            YES,
+            SIXTY_FOUR_BIT_ONLY,
+            NO
+        }
+
+        /**
+         * Tests whether an immediate can be encoded for logical instructions.
+         *
+         * @param is64bit if true immediate is considered a 64-bit pattern. If false we may use a
+         *            64-bit instruction to load the 32-bit pattern into a register.
+         * @return enum specifying whether immediate can be used for 32- and 64-bit logical
+         *         instructions ({@code #Representable.YES}), for 64-bit instructions only (
+         *         {@code #Representable.SIXTY_FOUR_BIT_ONLY}) or not at all (
+         *         {@code #Representable.NO} ).
+         */
+        public static Representable isRepresentable(boolean is64bit, long immediate) {
+            int pos = getLogicalImmTablePos(is64bit, immediate);
+            if (pos < 0) {
+                // if 32bit instruction we can try again as 64bit immediate which may succeed.
+                // i.e. 0xffffffff fails as a 32bit immediate but works as 64bit one.
+                if (!is64bit) {
+                    assert NumUtil.isUnsignedNbit(32, immediate);
+                    pos = getLogicalImmTablePos(true, immediate);
+                    return pos >= 0 ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.NO;
+                }
+                return Representable.NO;
+            }
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            return imm.only64bit() ? Representable.SIXTY_FOUR_BIT_ONLY : Representable.YES;
+        }
+
+        public static Representable isRepresentable(int immediate) {
+            return isRepresentable(false, immediate & 0xFFFF_FFFFL);
+        }
+
+        public static int getLogicalImmEncoding(boolean is64bit, long value) {
+            int pos = getLogicalImmTablePos(is64bit, value);
+            assert pos >= 0 : "Value cannot be represented as logical immediate";
+            Immediate imm = IMMEDIATE_TABLE[pos];
+            assert is64bit || !imm.only64bit() : "Immediate can only be represented for 64bit, but 32bit instruction specified";
+            return IMMEDIATE_TABLE[pos].encoding;
+        }
+
+        /**
+         * @param is64bit if true also allow 64-bit only encodings to be returned.
+         * @return If positive the return value is the position into the IMMEDIATE_TABLE for the
+         *         given immediate, if negative the immediate cannot be encoded.
+         */
+        private static int getLogicalImmTablePos(boolean is64bit, long value) {
+            Immediate imm;
+            if (!is64bit) {
+                // 32bit instructions can only have 32bit immediates.
+                if (!NumUtil.isUnsignedNbit(32, value)) {
+                    return -1;
+                }
+                // If we have a 32bit instruction (and therefore immediate) we have to duplicate it
+                // across 64bit to find it in the table.
+                imm = new Immediate(value << 32 | value);
+            } else {
+                imm = new Immediate(value);
+            }
+            int pos = Arrays.binarySearch(IMMEDIATE_TABLE, imm);
+            if (pos < 0) {
+                return -1;
+            }
+            if (!is64bit && IMMEDIATE_TABLE[pos].only64bit()) {
+                return -1;
+            }
+            return pos;
+        }
+
+        /**
+         * To quote 5.4.2: [..] an immediate is a 32 or 64 bit pattern viewed as a vector of
+         * identical elements of size e = 2, 4, 8, 16, 32 or (in the case of bimm64) 64 bits. Each
+         * element contains the same sub-pattern: a single run of 1 to e-1 non-zero bits, rotated by
+         * 0 to e-1 bits. It is encoded in the following: 10-16: rotation amount (6bit) starting
+         * from 1s in the LSB (i.e. 0111->1011->1101->1110) 16-22: This stores a combination of the
+         * number of set bits and the pattern size. The pattern size is encoded as follows (x is
+         * used to store the number of 1 bits - 1) e pattern 2 1111xx 4 1110xx 8 110xxx 16 10xxxx 32
+         * 0xxxxx 64 xxxxxx 22: if set we have an instruction with 64bit pattern?
+         */
+        private static final class Immediate implements Comparable<Immediate> {
+            public final long imm;
+            public final int encoding;
+
+            public Immediate(long imm, boolean is64, int s, int r) {
+                this.imm = imm;
+                this.encoding = computeEncoding(is64, s, r);
+            }
+
+            // Used to be able to binary search for an immediate in the table.
+            public Immediate(long imm) {
+                this(imm, false, 0, 0);
+            }
+
+            /**
+             * Returns true if this pattern is only representable as 64bit.
+             */
+            public boolean only64bit() {
+                return (encoding & (1 << ImmediateSizeOffset)) != 0;
+            }
+
+            private static int computeEncoding(boolean is64, int s, int r) {
+                int sf = is64 ? 1 : 0;
+                return sf << ImmediateSizeOffset | r << ImmediateRotateOffset | s << ImmediateOffset;
+            }
+
+            @Override
+            public int compareTo(Immediate o) {
+                return Long.compare(imm, o.imm);
+            }
+        }
+
+        private static Immediate[] buildImmediateTable() {
+            final int nrImmediates = 5334;
+            final Immediate[] table = new Immediate[nrImmediates];
+            int nrImms = 0;
+            for (int logE = 1; logE <= 6; logE++) {
+                int e = 1 << logE;
+                long mask = NumUtil.getNbitNumberLong(e);
+                for (int nrOnes = 1; nrOnes < e; nrOnes++) {
+                    long val = (1L << nrOnes) - 1;
+                    // r specifies how much we rotate the value
+                    for (int r = 0; r < e; r++) {
+                        long immediate = (val >>> r | val << (e - r)) & mask;
+                        // Duplicate pattern to fill whole 64bit range.
+                        switch (logE) {
+                            case 1:
+                                immediate |= immediate << 2;
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 2:
+                                immediate |= immediate << 4;
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 3:
+                                immediate |= immediate << 8;
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 4:
+                                immediate |= immediate << 16;
+                                immediate |= immediate << 32;
+                                break;
+                            case 5:
+                                immediate |= immediate << 32;
+                                break;
+                        }
+                        // 5 - logE can underflow to -1, but we shift this bogus result
+                        // out of the masked area.
+                        int sizeEncoding = (1 << (5 - logE)) - 1;
+                        int s = ((sizeEncoding << (logE + 1)) & 0x3f) | (nrOnes - 1);
+                        table[nrImms++] = new Immediate(immediate, /* is64bit */e == 64, s, r);
+                    }
+                }
+            }
+            Arrays.sort(table);
+            assert nrImms == nrImmediates : nrImms + " instead of " + nrImmediates + " in table.";
+            assert checkDuplicates(table) : "Duplicate values in table.";
+            return table;
+        }
+
+        private static boolean checkDuplicates(Immediate[] table) {
+            for (int i = 0; i < table.length - 1; i++) {
+                if (table[i].imm >= table[i + 1].imm) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static final int RdOffset = 0;
+    private static final int Rs1Offset = 5;
+    private static final int Rs2Offset = 16;
+    private static final int Rs3Offset = 10;
+    private static final int RtOffset = 0;
+
+    /**
+     * Enumeration of all different instruction kinds: General32/64 are the general instructions
+     * (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for
+     * the 32/64bit float operations
+     */
+    protected enum InstructionType {
+        General32(0x00000000, 32, true),
+        General64(0x80000000, 64, true),
+        FP32(0x00000000, 32, false),
+        FP64(0x00400000, 64, false);
+
+        public final int encoding;
+        public final int width;
+        public final boolean isGeneral;
+
+        private InstructionType(int encoding, int width, boolean isGeneral) {
+            this.encoding = encoding;
+            this.width = width;
+            this.isGeneral = isGeneral;
+        }
+
+        public static InstructionType generalFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? General32 : General64;
+        }
+
+        public static InstructionType floatFromSize(int size) {
+            assert size == 32 || size == 64;
+            return size == 32 ? FP32 : FP64;
+        }
+
+    }
+
+    private static final int ImmediateOffset = 10;
+    private static final int ImmediateRotateOffset = 16;
+    private static final int ImmediateSizeOffset = 22;
+    private static final int ExtendTypeOffset = 13;
+
+    private static final int AddSubImmOp = 0x11000000;
+    // If 1 the immediate is interpreted as being left-shifted by 12 bits.
+    private static final int AddSubShiftOffset = 22;
+    private static final int AddSubSetFlag = 0x20000000;
+
+    private static final int LogicalImmOp = 0x12000000;
+
+    private static final int MoveWideImmOp = 0x12800000;
+    private static final int MoveWideImmOffset = 5;
+    private static final int MoveWideShiftOffset = 21;
+
+    private static final int BitfieldImmOp = 0x13000000;
+
+    private static final int AddSubShiftedOp = 0x0B000000;
+    private static final int ShiftTypeOffset = 22;
+
+    private static final int AddSubExtendedOp = 0x0B200000;
+
+    private static final int MulOp = 0x1B000000;
+    private static final int DataProcessing1SourceOp = 0x5AC00000;
+    private static final int DataProcessing2SourceOp = 0x1AC00000;
+
+    private static final int Fp1SourceOp = 0x1E204000;
+    private static final int Fp2SourceOp = 0x1E200800;
+    private static final int Fp3SourceOp = 0x1F000000;
+
+    private static final int FpConvertOp = 0x1E200000;
+    private static final int FpImmOp = 0x1E201000;
+    private static final int FpImmOffset = 13;
+
+    private static final int FpCmpOp = 0x1E202000;
+
+    private static final int PcRelImmHiOffset = 5;
+    private static final int PcRelImmLoOffset = 29;
+
+    private static final int PcRelImmOp = 0x10000000;
+
+    private static final int UnconditionalBranchImmOp = 0x14000000;
+    private static final int UnconditionalBranchRegOp = 0xD6000000;
+    private static final int CompareBranchOp = 0x34000000;
+
+    private static final int ConditionalBranchImmOffset = 5;
+
+    private static final int ConditionalSelectOp = 0x1A800000;
+    private static final int ConditionalConditionOffset = 12;
+
+    private static final int LoadStoreScaledOp = 0x39000000;
+    private static final int LoadStoreUnscaledOp = 0x38000000;
+    private static final int LoadStoreRegisterOp = 0x38200800;
+    private static final int LoadLiteralOp = 0x18000000;
+    private static final int LoadStorePostIndexedOp = 0x38000400;
+    private static final int LoadStorePreIndexedOp = 0x38000C00;
+
+    private static final int LoadStoreUnscaledImmOffset = 12;
+    private static final int LoadStoreScaledImmOffset = 10;
+    private static final int LoadStoreScaledRegOffset = 12;
+    private static final int LoadStoreIndexedImmOffset = 12;
+    private static final int LoadStoreTransferSizeOffset = 30;
+    private static final int LoadStoreFpFlagOffset = 26;
+    private static final int LoadLiteralImmeOffset = 5;
+
+    private static final int LogicalShiftOp = 0x0A000000;
+
+    private static final int ExceptionOp = 0xD4000000;
+    private static final int SystemImmediateOffset = 5;
+
+    @SuppressWarnings("unused") private static final int SimdImmediateOffset = 16;
+
+    private static final int BarrierOp = 0xD503301F;
+    private static final int BarrierKindOffset = 8;
+
+    /**
+     * Encoding for all instructions.
+     */
+    private enum Instruction {
+        BCOND(0x54000000),
+        CBNZ(0x01000000),
+        CBZ(0x00000000),
+
+        B(0x00000000),
+        BL(0x80000000),
+        BR(0x001F0000),
+        BLR(0x003F0000),
+        RET(0x005F0000),
+
+        LDR(0x00000000),
+        LDRS(0x00800000),
+        LDXR(0x081f7c00),
+        LDAR(0x8dffc00),
+        LDAXR(0x85ffc00),
+
+        STR(0x00000000),
+        STXR(0x08007c00),
+        STLR(0x089ffc00),
+        STLXR(0x0800fc00),
+
+        ADR(0x00000000),
+        ADRP(0x80000000),
+
+        ADD(0x00000000),
+        ADDS(ADD.encoding | AddSubSetFlag),
+        SUB(0x40000000),
+        SUBS(SUB.encoding | AddSubSetFlag),
+
+        NOT(0x00200000),
+        AND(0x00000000),
+        BIC(AND.encoding | NOT.encoding),
+        ORR(0x20000000),
+        ORN(ORR.encoding | NOT.encoding),
+        EOR(0x40000000),
+        EON(EOR.encoding | NOT.encoding),
+        ANDS(0x60000000),
+        BICS(ANDS.encoding | NOT.encoding),
+
+        ASRV(0x00002800),
+        RORV(0x00002C00),
+        LSRV(0x00002400),
+        LSLV(0x00002000),
+
+        CLS(0x00001400),
+        CLZ(0x00001000),
+        RBIT(0x00000000),
+        REVX(0x00000C00),
+        REVW(0x00000800),
+
+        MOVN(0x00000000),
+        MOVZ(0x40000000),
+        MOVK(0x60000000),
+
+        CSEL(0x00000000),
+        CSNEG(0x40000400),
+        CSINC(0x00000400),
+
+        BFM(0x20000000),
+        SBFM(0x00000000),
+        UBFM(0x40000000),
+        EXTR(0x13800000),
+
+        MADD(0x00000000),
+        MSUB(0x00008000),
+        SDIV(0x00000C00),
+        UDIV(0x00000800),
+
+        FMOV(0x00000000),
+        FMOVCPU2FPU(0x00070000),
+        FMOVFPU2CPU(0x00060000),
+
+        FCVTDS(0x00028000),
+        FCVTSD(0x00020000),
+
+        FCVTZS(0x00180000),
+        SCVTF(0x00020000),
+
+        FABS(0x00008000),
+        FSQRT(0x00018000),
+        FNEG(0x00010000),
+
+        FRINTZ(0x00058000),
+
+        FADD(0x00002000),
+        FSUB(0x00003000),
+        FMUL(0x00000000),
+        FDIV(0x00001000),
+        FMAX(0x00004000),
+        FMIN(0x00005000),
+
+        FMADD(0x00000000),
+        FMSUB(0x00008000),
+
+        FCMP(0x00000000),
+        FCMPZERO(0x00000008),
+        FCCMP(0x1E200400),
+        FCSEL(0x1E200C00),
+
+        INS(0x4e081c00),
+        UMOV(0x4e083c00),
+
+        CNT(0xe205800),
+        USRA(0x6f001400),
+
+        HLT(0x00400000),
+        BRK(0x00200000),
+
+        CLREX(0xd5033f5f),
+        HINT(0xD503201F),
+        DMB(0x000000A0),
+
+        BLR_NATIVE(0xc0000000);
+
+        public final int encoding;
+
+        private Instruction(int encoding) {
+            this.encoding = encoding;
+        }
+
+    }
+
+    public enum ShiftType {
+        LSL(0),
+        LSR(1),
+        ASR(2),
+        ROR(3);
+
+        public final int encoding;
+
+        private ShiftType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    public enum ExtendType {
+        UXTB(0),
+        UXTH(1),
+        UXTW(2),
+        UXTX(3),
+        SXTB(4),
+        SXTH(5),
+        SXTW(6),
+        SXTX(7);
+
+        public final int encoding;
+
+        private ExtendType(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Condition Flags for branches. See 4.3
+     */
+    public enum ConditionFlag {
+        // Integer | Floating-point meanings
+        /**
+         * Equal | Equal.
+         */
+        EQ(0x0),
+        /**
+         * Not Equal | Not equal or unordered.
+         */
+        NE(0x1),
+        /**
+         * Unsigned Higher or Same | Greater than, equal or unordered.
+         */
+        HS(0x2),
+        /**
+         * unsigned lower | less than.
+         */
+        LO(0x3),
+        /**
+         * minus (negative) | less than.
+         */
+        MI(0x4),
+        /**
+         * plus (positive or zero) | greater than, equal or unordered.
+         */
+        PL(0x5),
+        /**
+         * overflow set | unordered.
+         */
+        VS(0x6),
+        /**
+         * overflow clear | ordered.
+         */
+        VC(0x7),
+        /**
+         * unsigned higher | greater than or unordered.
+         */
+        HI(0x8),
+        /**
+         * unsigned lower or same | less than or equal.
+         */
+        LS(0x9),
+        /**
+         * signed greater than or equal | greater than or equal.
+         */
+        GE(0xA),
+        /**
+         * signed less than | less than or unordered.
+         */
+        LT(0xB),
+        /**
+         * signed greater than | greater than.
+         */
+        GT(0xC),
+        /**
+         * signed less than or equal | less than, equal or unordered.
+         */
+        LE(0xD),
+        /**
+         * always | always.
+         */
+        AL(0xE),
+        /**
+         * always | always (identical to AL, just to have valid 0b1111 encoding).
+         */
+        NV(0xF);
+
+        public final int encoding;
+
+        private ConditionFlag(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return ConditionFlag specified by decoding.
+         */
+        public static ConditionFlag fromEncoding(int encoding) {
+            return values()[encoding];
+        }
+
+        public ConditionFlag negate() {
+            switch (this) {
+                case EQ:
+                    return NE;
+                case NE:
+                    return EQ;
+                case HS:
+                    return LO;
+                case LO:
+                    return HS;
+                case MI:
+                    return PL;
+                case PL:
+                    return MI;
+                case VS:
+                    return VC;
+                case VC:
+                    return VS;
+                case HI:
+                    return LS;
+                case LS:
+                    return HI;
+                case GE:
+                    return LT;
+                case LT:
+                    return GE;
+                case GT:
+                    return LE;
+                case LE:
+                    return GT;
+                case AL:
+                case NV:
+                default:
+                    throw JVMCIError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public AArch64Assembler(TargetDescription target) {
+        super(target);
+    }
+
+    /* Conditional Branch (5.2.1) */
+
+    /**
+     * Branch conditionally.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void b(ConditionFlag condition, int imm21) {
+        b(condition, imm21, -1);
+    }
+
+    /**
+     * Branch conditionally. Inserts instruction into code buffer at pos.
+     *
+     * @param condition may not be null.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void b(ConditionFlag condition, int imm21, int pos) {
+        if (pos == -1) {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding);
+        } else {
+            emitInt(Instruction.BCOND.encoding | getConditionalBranchImm(imm21) | condition.encoding, pos);
+        }
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbnz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, -1);
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbnz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBNZ, pos);
+    }
+
+    /**
+     * Compare and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     */
+    protected void cbz(int size, Register reg, int imm21) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, -1);
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param imm21 Signed 21-bit offset, has to be word aligned.
+     * @param pos Position at which instruction is inserted into buffer. -1 means insert at end.
+     */
+    protected void cbz(int size, Register reg, int imm21, int pos) {
+        conditionalBranchInstruction(reg, imm21, generalFromSize(size), Instruction.CBZ, pos);
+    }
+
+    private void conditionalBranchInstruction(Register reg, int imm21, InstructionType type, Instruction instr, int pos) {
+        assert reg.getRegisterCategory().equals(CPU);
+        int instrEncoding = instr.encoding | CompareBranchOp;
+        if (pos == -1) {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg));
+        } else {
+            emitInt(type.encoding | instrEncoding | getConditionalBranchImm(imm21) | rd(reg), pos);
+        }
+    }
+
+    private static int getConditionalBranchImm(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21) && (imm21 & 0x3) == 0 : "Immediate has to be 21bit signed number and word aligned";
+        int imm = (imm21 & NumUtil.getNbitNumberInt(21)) >> 2;
+        return imm << ConditionalBranchImmOffset;
+    }
+
+    /* Unconditional Branch (immediate) (5.2.2) */
+
+    /**
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    protected void b(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, -1);
+    }
+
+    /**
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     * @param pos Position where instruction is inserted into code buffer.
+     */
+    protected void b(int imm28, int pos) {
+        unconditionalBranchImmInstruction(imm28, Instruction.B, pos);
+    }
+
+    /**
+     * Branch and link return address to register X30.
+     *
+     * @param imm28 Signed 28-bit offset, has to be word aligned.
+     */
+    public void bl(int imm28) {
+        unconditionalBranchImmInstruction(imm28, Instruction.BL, -1);
+    }
+
+    private void unconditionalBranchImmInstruction(int imm28, Instruction instr, int pos) {
+        assert NumUtil.isSignedNbit(28, imm28) && (imm28 & 0x3) == 0 : "Immediate has to be 28bit signed number and word aligned";
+        int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2;
+        int instrEncoding = instr.encoding | UnconditionalBranchImmOp;
+        if (pos == -1) {
+            emitInt(instrEncoding | imm);
+        } else {
+            emitInt(instrEncoding | imm, pos);
+        }
+    }
+
+    /* Unconditional Branch (register) (5.2.3) */
+
+    /**
+     * Branches to address in register and writes return address into register X30.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void blr(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.BLR);
+    }
+
+    /**
+     * Branches to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    protected void br(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.BR);
+    }
+
+    /**
+     * Return to address in register.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void ret(Register reg) {
+        unconditionalBranchRegInstruction(reg, Instruction.RET);
+    }
+
+    private void unconditionalBranchRegInstruction(Register reg, Instruction instr) {
+        assert reg.getRegisterCategory().equals(CPU) && !reg.equals(zr) && !reg.equals(sp);
+        final int instrEncoding = instr.encoding | UnconditionalBranchRegOp;
+        emitInt(instrEncoding | rs1(reg));
+    }
+
+    /* Load-Store Single Register (5.3.1) */
+
+    /**
+     * Loads a srcSize value from address into rt zero-extending it.
+     *
+     * @param srcSize size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void ldr(int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32 || srcSize == 64;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(rt, address, InstructionType.General32, Instruction.LDR, transferSize);
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32, but may not be equivalent to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    protected void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert (srcSize == 8 || srcSize == 16 || srcSize == 32) && srcSize != targetSize;
+        int transferSize = NumUtil.log2Ceil(srcSize / 8);
+        loadStoreInstruction(rt, address, generalFromSize(targetSize), Instruction.LDRS, transferSize);
+    }
+
+    /**
+     * Stores register rt into memory pointed by address.
+     *
+     * @param destSize number of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void str(int destSize, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(CPU);
+        assert destSize == 8 || destSize == 16 || destSize == 32 || destSize == 64;
+        int transferSize = NumUtil.log2Ceil(destSize / 8);
+        loadStoreInstruction(rt, address, InstructionType.General64, Instruction.STR, transferSize);
+    }
+
+    private void loadStoreInstruction(Register reg, AArch64Address address, InstructionType type, Instruction instr, int log2TransferSize) {
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int is32Bit = type.width == 32 ? 1 << ImmediateSizeOffset : 0;
+        int isFloat = !type.isGeneral ? 1 << LoadStoreFpFlagOffset : 0;
+        int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase()));
+                break;
+            case IMMEDIATE_UNSCALED:
+                emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase()));
+                break;
+            case BASE_REGISTER_ONLY:
+                emitInt(memop | LoadStoreScaledOp | rs1(address.getBase()));
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+            case REGISTER_OFFSET:
+                ExtendType extendType = address.getAddressingMode() == AddressingMode.EXTENDED_REGISTER_OFFSET ? address.getExtendType() : ExtendType.UXTX;
+                boolean shouldScale = address.isScaled() && log2TransferSize != 0;
+                emitInt(memop | LoadStoreRegisterOp | rs2(address.getOffset()) | extendType.encoding << ExtendTypeOffset | (shouldScale ? 1 : 0) << LoadStoreScaledRegOffset | rs1(address.getBase()));
+                break;
+            case PC_LITERAL:
+                assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger";
+                transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset;
+                emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset);
+                break;
+            case IMMEDIATE_POST_INDEXED:
+                emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            case IMMEDIATE_PRE_INDEXED:
+                emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /* Load-Store Exclusive (5.3.6) */
+
+    /**
+     * Load address exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void ldxr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDXR);
+    }
+
+    /**
+     * Store address exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void stxr(int size, Register rs, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(rs, rt, address, transferSize, Instruction.STXR);
+    }
+
+    /* Load-Acquire/Store-Release (5.3.7) */
+
+    /* non exclusive access */
+    /**
+     * Load acquire. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void ldar(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDAR);
+    }
+
+    /**
+     * Store-release. Natural alignment of address is required.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    protected void stlr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        // Hack: Passing the zero-register means it is ignored when building the encoding.
+        exclusiveStoreInstruction(AArch64.r0, rt, address, transferSize, Instruction.STLR);
+    }
+
+    /* exclusive access */
+    /**
+     * Load acquire exclusive. Natural alignment of address is required.
+     *
+     * @param size size of memory read in bits. Must be 8, 16, 32 or 64.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    public void ldaxr(int size, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveLoadInstruction(rt, address, transferSize, Instruction.LDAXR);
+    }
+
+    /**
+     * Store-release exclusive. Natural alignment of address is required. rs and rt may not point to
+     * the same register.
+     *
+     * @param size size of bits written to memory. Must be 8, 16, 32 or 64.
+     * @param rs general purpose register. Set to exclusive access status. 0 means success,
+     *            everything else failure. May not be null, or stackpointer.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address Has to be {@link AddressingMode#BASE_REGISTER_ONLY BASE_REGISTER_ONLY}. May
+     *            not be null.
+     */
+    public void stlxr(int size, Register rs, Register rt, AArch64Address address) {
+        assert size == 8 || size == 16 || size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        exclusiveStoreInstruction(rs, rt, address, transferSize, Instruction.STLXR);
+    }
+
+    private void exclusiveLoadInstruction(Register reg, AArch64Address address, int log2TransferSize, Instruction instr) {
+        assert address.getAddressingMode() == AddressingMode.BASE_REGISTER_ONLY;
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert reg.getRegisterCategory().equals(CPU);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int instrEncoding = instr.encoding;
+        emitInt(transferSizeEncoding | instrEncoding | 1 << ImmediateSizeOffset | rt(reg) | rs1(address.getBase()));
+    }
+
+    /**
+     * Stores data from rt into address and sets rs to the returned exclusive access status.
+     *
+     * @param rs general purpose register into which the exclusive access status is written. May not
+     *            be null.
+     * @param rt general purpose register containing data to be written to memory at address. May
+     *            not be null
+     * @param address Address in base register without offset form specifying where rt is written
+     *            to.
+     * @param log2TransferSize log2Ceil of memory transfer size.
+     */
+    private void exclusiveStoreInstruction(Register rs, Register rt, AArch64Address address, int log2TransferSize, Instruction instr) {
+        assert address.getAddressingMode() == AddressingMode.BASE_REGISTER_ONLY;
+        assert log2TransferSize >= 0 && log2TransferSize < 4;
+        assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
+        int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+        int instrEncoding = instr.encoding;
+        emitInt(transferSizeEncoding | instrEncoding | rs2(rs) | rt(rt) | rs1(address.getBase()));
+    }
+
+    /* PC-relative Address Calculation (5.4.4) */
+
+    /**
+     * Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of
+     * the PC with its bottom 12-bits cleared, writing the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm Signed 33-bit offset with lower 12bits clear.
+     */
+    // protected void adrp(Register dst, long imm) {
+    // assert (imm & NumUtil.getNbitNumberInt(12)) == 0 : "Lower 12-bit of immediate must be zero.";
+    // assert NumUtil.isSignedNbit(33, imm);
+    // addressCalculationInstruction(dst, (int) (imm >>> 12), Instruction.ADRP);
+    // }
+
+    /**
+     * Adds a 21-bit signed offset to the program counter and writes the result to dst.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm21 Signed 21-bit offset.
+     */
+    public void adr(Register dst, int imm21) {
+        addressCalculationInstruction(dst, imm21, Instruction.ADR);
+    }
+
+    private void addressCalculationInstruction(Register dst, int imm21, Instruction instr) {
+        assert dst.getRegisterCategory().equals(CPU);
+        int instrEncoding = instr.encoding | PcRelImmOp;
+        emitInt(instrEncoding | rd(dst) | getPcRelativeImmEncoding(imm21));
+    }
+
+    private static int getPcRelativeImmEncoding(int imm21) {
+        assert NumUtil.isSignedNbit(21, imm21);
+        int imm = imm21 & NumUtil.getNbitNumberInt(21);
+        // higher 19 bit
+        int immHi = (imm >> 2) << PcRelImmHiOffset;
+        // lower 2 bit
+        int immLo = (imm & 0x3) << PcRelImmLoOffset;
+        return immHi | immLo;
+    }
+
+    /* Arithmetic (Immediate) (5.4.1) */
+
+    /**
+     * dst = src + aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void add(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void adds(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src - aimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void sub(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param aimm arithmetic immediate. Either unsigned 12-bit value or unsigned 24-bit value with
+     *            the lower 12-bit cleared.
+     */
+    protected void subs(int size, Register dst, Register src, int aimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(zr);
+        addSubImmInstruction(dst, src, aimm, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubImmInstruction(Register dst, Register src, int aimm, InstructionType type, Instruction instr) {
+        int instrEncoding = instr.encoding | AddSubImmOp;
+        emitInt(type.encoding | instrEncoding | encodeAimm(aimm) | rd(dst) | rs1(src));
+    }
+
+    /**
+     * Encodes arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with
+     *            the lower 12 bits 0.
+     * @return Representation of immediate for use with arithmetic instructions.
+     */
+    private static int encodeAimm(int imm) {
+        assert isAimm(imm) : "Immediate has to be legal arithmetic immediate value " + imm;
+        if (NumUtil.isUnsignedNbit(12, imm)) {
+            return imm << ImmediateOffset;
+        } else {
+            // First 12 bit are 0, so shift immediate 12 bit and set flag to indicate
+            // shifted immediate value.
+            return (imm >>> 12 << ImmediateOffset) | (1 << AddSubShiftOffset);
+        }
+    }
+
+    /**
+     * Checks whether immediate can be encoded as an arithmetic immediate.
+     *
+     * @param imm Immediate has to be either an unsigned 12bit value or un unsigned 24bit value with
+     *            the lower 12 bits 0.
+     * @return true if valid arithmetic immediate, false otherwise.
+     */
+    protected static boolean isAimm(int imm) {
+        return NumUtil.isUnsignedNbit(12, imm) || NumUtil.isUnsignedNbit(12, imm >>> 12) && (imm & 0xfff) == 0;
+    }
+
+    /* Logical (immediate) (5.4.2) */
+
+    /**
+     * dst = src & bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void and(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.AND);
+    }
+
+    /**
+     * dst = src & bimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void ands(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(sp);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.ANDS);
+    }
+
+    /**
+     * dst = src ^ bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    public void eor(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.EOR);
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link LogicalImmediateTable} for exact definition.
+     */
+    protected void orr(int size, Register dst, Register src, long bimm) {
+        assert !dst.equals(zr);
+        assert !src.equals(sp);
+        logicalImmInstruction(dst, src, bimm, generalFromSize(size), Instruction.ORR);
+    }
+
+    protected void logicalImmInstruction(Register dst, Register src, long bimm, InstructionType type, Instruction instr) {
+        // Mask higher bits off, since we always pass longs around even for the 32-bit instruction.
+        long bimmValue;
+        if (type == InstructionType.General32) {
+            assert (bimm >> 32) == 0 || (bimm >> 32) == -1L : "Higher order bits for 32-bit instruction must either all be 0 or 1.";
+            bimmValue = bimm & NumUtil.getNbitNumberLong(32);
+        } else {
+            bimmValue = bimm;
+        }
+        int immEncoding = LogicalImmediateTable.getLogicalImmEncoding(type == InstructionType.General64, bimmValue);
+        int instrEncoding = instr.encoding | LogicalImmOp;
+        emitInt(type.encoding | instrEncoding | immEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Move (wide immediate) (5.4.3) */
+
+    /**
+     * dst = uimm16 << shiftAmt.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movz(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(dst, uimm16, shiftAmt, generalFromSize(size), Instruction.MOVZ);
+    }
+
+    /**
+     * dst = ~(uimm16 << shiftAmt).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param shiftAmt amount by which uimm16 is left shifted. Can be any multiple of 16 smaller
+     *            than size.
+     */
+    protected void movn(int size, Register dst, int uimm16, int shiftAmt) {
+        moveWideImmInstruction(dst, uimm16, shiftAmt, generalFromSize(size), Instruction.MOVN);
+    }
+
+    /**
+     * dst<pos+15:pos> = uimm16.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param uimm16 16-bit unsigned immediate
+     * @param pos position into which uimm16 is inserted. Can be any multiple of 16 smaller than
+     *            size.
+     */
+    protected void movk(int size, Register dst, int uimm16, int pos) {
+        moveWideImmInstruction(dst, uimm16, pos, generalFromSize(size), Instruction.MOVK);
+    }
+
+    private void moveWideImmInstruction(Register dst, int uimm16, int shiftAmt, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert NumUtil.isUnsignedNbit(16, uimm16) : "Immediate has to be unsigned 16bit";
+        assert shiftAmt == 0 || shiftAmt == 16 || (type == InstructionType.General64 && (shiftAmt == 32 || shiftAmt == 48)) : "Invalid shift amount: " + shiftAmt;
+        int shiftValue = shiftAmt >> 4;
+        int instrEncoding = instr.encoding | MoveWideImmOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | uimm16 << MoveWideImmOffset | shiftValue << MoveWideShiftOffset);
+    }
+
+    /* Bitfield Operations (5.4.5) */
+
+    /**
+     * Bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void bfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.BFM);
+    }
+
+    /**
+     * Unsigned bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void ubfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.UBFM);
+    }
+
+    /**
+     * Signed bitfield move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param r must be in the range 0 to size - 1
+     * @param s must be in the range 0 to size - 1
+     */
+    protected void sbfm(int size, Register dst, Register src, int r, int s) {
+        bitfieldInstruction(dst, src, r, s, generalFromSize(size), Instruction.SBFM);
+    }
+
+    private void bitfieldInstruction(Register dst, Register src, int r, int s, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp) && !dst.equals(zr);
+        assert !src.equals(sp) && !src.equals(zr);
+        assert s >= 0 && s < type.width && r >= 0 && r < type.width;
+        int instrEncoding = instr.encoding | BitfieldImmOp;
+        int sf = type == InstructionType.General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | instrEncoding | sf | r << ImmediateRotateOffset | s << ImmediateOffset | rd(dst) | rs1(src));
+    }
+
+    /* Extract (Immediate) (5.4.6) */
+
+    /**
+     * Extract. dst = src1:src2<lsb+31:lsb>
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param lsb must be in range 0 to size - 1.
+     */
+    protected void extr(int size, Register dst, Register src1, Register src2, int lsb) {
+        extractInstruction(dst, src1, src2, lsb, generalFromSize(size));
+    }
+
+    private void extractInstruction(Register dst, Register src1, Register src2, int lsb, InstructionType type) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert lsb >= 0 && lsb < type.width;
+        int sf = type == InstructionType.General64 ? 1 << ImmediateSizeOffset : 0;
+        emitInt(type.encoding | Instruction.EXTR.encoding | sf | lsb << ImmediateOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (shifted register) (5.5.1) */
+
+    /**
+     * dst = src1 + shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src1 - shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param imm must be in range 0 to size - 1.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
+        addSubShiftedInstruction(dst, src1, src2, shiftType, imm, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubShiftedInstruction(Register dst, Register src1, Register src2, ShiftType shiftType, int imm, InstructionType type, Instruction instr) {
+        assert shiftType != ShiftType.ROR;
+        assert imm >= 0 && imm < type.width;
+        int instrEncoding = instr.encoding | AddSubShiftedOp;
+        emitInt(type.encoding | instrEncoding | imm << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Arithmetic (extended register) (5.5.2) */
+    /**
+     * dst = src1 + extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    public void add(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.ADD);
+    }
+
+    /**
+     * dst = src1 + extendType(src2) << imm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void adds(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.ADDS);
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(zr);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.SUB);
+    }
+
+    /**
+     * dst = src1 - extendType(src2) << imm and sets flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer..
+     * @param src1 general purpose register. May not be null or zero-register.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param extendType defines how src2 is extended to the same size as src1.
+     * @param shiftAmt must be in range 0 to 4.
+     */
+    protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
+        assert !dst.equals(sp);
+        assert !src1.equals(zr);
+        assert !src2.equals(sp);
+        addSubExtendedInstruction(dst, src1, src2, extendType, shiftAmt, generalFromSize(size), Instruction.SUBS);
+    }
+
+    private void addSubExtendedInstruction(Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt, InstructionType type, Instruction instr) {
+        assert shiftAmt >= 0 && shiftAmt <= 4;
+        int instrEncoding = instr.encoding | AddSubExtendedOp;
+        emitInt(type.encoding | instrEncoding | shiftAmt << ImmediateOffset | extendType.encoding << ExtendTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Logical (shifted register) (5.5.3) */
+    /**
+     * dst = src1 & shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void and(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.AND);
+    }
+
+    /**
+     * dst = src1 & shiftType(src2, imm) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void ands(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ANDS);
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bic(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.BIC);
+    }
+
+    /**
+     * dst = src1 & ~(shiftType(src2, imm)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void bics(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.BICS);
+    }
+
+    /**
+     * dst = src1 ^ ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eon(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.EON);
+    }
+
+    /**
+     * dst = src1 ^ shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void eor(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.EOR);
+    }
+
+    /**
+     * dst = src1 | shiftType(src2, imm).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orr(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ORR);
+    }
+
+    /**
+     * dst = src1 | ~(shiftType(src2, imm)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType all types allowed, may not be null.
+     * @param shiftAmt must be in range 0 to size - 1.
+     */
+    protected void orn(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        logicalRegInstruction(dst, src1, src2, shiftType, shiftAmt, generalFromSize(size), Instruction.ORN);
+    }
+
+    private void logicalRegInstruction(Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert shiftAmt >= 0 && shiftAmt < type.width;
+        int instrEncoding = instr.encoding | LogicalShiftOp;
+        emitInt(type.encoding | instrEncoding | shiftAmt << ImmediateOffset | shiftType.encoding << ShiftTypeOffset | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Variable Shift (5.5.4) */
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void asr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.ASRV);
+    }
+
+    /**
+     * dst = src1 << (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsl(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.LSLV);
+    }
+
+    /**
+     * dst = src1 >>> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void lsr(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.LSRV);
+    }
+
+    /**
+     * dst = rotateRight(src1, (src2 & log2(size))).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    protected void ror(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.RORV);
+    }
+
+    /* Bit Operations (5.5.5) */
+
+    /**
+     * Counts leading sign bits. Sets Wd to the number of consecutive bits following the topmost bit
+     * in dst, that are the same as the topmost bit. The count does not include the topmost bit
+     * itself , so the result will be in the range 0 to size-1 inclusive.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void cls(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.CLS);
+    }
+
+    /**
+     * Counts leading zeros.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    public void clz(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.CLZ);
+    }
+
+    /**
+     * Reverses bits.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, zero-register or the stackpointer.
+     * @param src source register. May not be null, zero-register or the stackpointer.
+     */
+    protected void rbit(int size, Register dst, Register src) {
+        dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.RBIT);
+    }
+
+    /**
+     * Reverses bytes.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src source register. May not be null or the stackpointer.
+     */
+    public void rev(int size, Register dst, Register src) {
+        if (size == 64) {
+            dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.REVX);
+        } else {
+            assert size == 32;
+            dataProcessing1SourceOp(dst, src, generalFromSize(size), Instruction.REVW);
+        }
+    }
+
+    /* Conditional Data Processing (5.5.6) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSEL);
+    }
+
+    /**
+     * Conditional select negate. dst = src1 if condition else -src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csneg(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSNEG);
+    }
+
+    /**
+     * Conditional increase. dst = src1 if condition else src2 + 1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param condition any condition flag. May not be null.
+     */
+    protected void csinc(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        conditionalSelectInstruction(dst, src1, src2, condition, generalFromSize(size), Instruction.CSINC);
+    }
+
+    private void conditionalSelectInstruction(Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        int instrEncoding = instr.encoding | ConditionalSelectOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Integer Multiply/Divide (5.6) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void madd(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(dst, src1, src2, src3, generalFromSize(size), Instruction.MADD);
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void msub(int size, Register dst, Register src1, Register src2, Register src3) {
+        mulInstruction(dst, src1, src2, src3, generalFromSize(size), Instruction.MSUB);
+    }
+
+    /**
+     * Signed multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011010 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2)[127:64]
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umulh(Register dst, Register src1, Register src2) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        emitInt(0b10011011110 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void umaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011101 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | 0b011111 << 10);
+    }
+
+    /**
+     * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    protected void smaddl(Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(0b10011011001 << 21 | dst.encoding | src1.encoding << 5 | src2.encoding << 16 | src3.encoding << 10);
+    }
+
+    private void mulInstruction(Register dst, Register src1, Register src2, Register src3, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        int instrEncoding = instr.encoding | MulOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /**
+     * Signed divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void sdiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.SDIV);
+    }
+
+    /**
+     * Unsigned divide. dst = src1 / src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void udiv(int size, Register dst, Register src1, Register src2) {
+        dataProcessing2SourceOp(dst, src1, src2, generalFromSize(size), Instruction.UDIV);
+    }
+
+    private void dataProcessing2SourceOp(Register dst, Register src1, Register src2, InstructionType type, Instruction instr) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        int instrEncoding = instr.encoding | DataProcessing2SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    private void dataProcessing1SourceOp(Register dst, Register src, InstructionType type, Instruction instr) {
+        int instrEncoding = instr.encoding | DataProcessing1SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating point operations */
+
+    /* Load-Store Single FP register (5.7.1.1) */
+    /**
+     * Floating point load.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fldr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(rt, address, InstructionType.FP32, Instruction.LDR, transferSize);
+    }
+
+    /**
+     * Floating point store.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param rt floating point register. May not be null.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    public void fstr(int size, Register rt, AArch64Address address) {
+        assert rt.getRegisterCategory().equals(SIMD);
+        assert size == 32 || size == 64;
+        int transferSize = NumUtil.log2Ceil(size / 8);
+        loadStoreInstruction(rt, address, InstructionType.FP64, Instruction.STR, transferSize);
+    }
+
+    /* Floating-point Move (register) (5.7.2) */
+
+    /**
+     * Floating point move.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void fmov(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FMOV);
+    }
+
+    /**
+     * Move size bits from floating point register unchanged to general purpose register.
+     *
+     * @param size number of bits read from memory into rt. Must be 32 or 64.
+     * @param dst general purpose register. May not be null, stack-pointer or zero-register
+     * @param src floating point register. May not be null.
+     */
+    protected void fmovFpu2Cpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(CPU);
+        assert src.getRegisterCategory().equals(SIMD);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVFPU2CPU);
+    }
+
+    /**
+     * Move size bits from general purpose register unchanged to floating point register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or stack-pointer.
+     */
+    protected void fmovCpu2Fpu(int size, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(CPU);
+        fmovCpuFpuInstruction(dst, src, size == 64, Instruction.FMOVCPU2FPU);
+    }
+
+    private void fmovCpuFpuInstruction(Register dst, Register src, boolean is64bit, Instruction instr) {
+        int instrEncoding = instr.encoding | FpConvertOp;
+        int sf = is64bit ? InstructionType.FP64.encoding | InstructionType.General64.encoding : InstructionType.FP32.encoding | InstructionType.General32.encoding;
+        emitInt(sf | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Move (immediate) (5.7.3) */
+
+    /**
+     * Move immediate into register.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    protected void fmov(int size, Register dst, double imm) {
+        fmovImmInstruction(dst, imm, floatFromSize(size));
+    }
+
+    private void fmovImmInstruction(Register dst, double imm, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        int immEncoding;
+        if (type == InstructionType.FP64) {
+            immEncoding = getDoubleImmediate(imm);
+        } else {
+            assert imm == (float) imm : "float mov must use an immediate that can be represented using a float.";
+            immEncoding = getFloatImmediate((float) imm);
+        }
+        int instrEncoding = Instruction.FMOV.encoding | FpImmOp;
+        emitInt(type.encoding | instrEncoding | immEncoding | rd(dst));
+    }
+
+    private static int getDoubleImmediate(double imm) {
+        assert isDoubleImmediate(imm);
+        // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long repr = Double.doubleToRawLongBits(imm);
+        int a = (int) (repr >>> 63) << 7;
+        int b = (int) ((repr >>> 61) & 0x1) << 6;
+        int cToH = (int) (repr >>> 48) & 0x3f;
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isDoubleImmediate(double imm) {
+        // Valid values will have the form:
+        // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+        // 0000.0000.0000.0000.0000.0000.0000.0000
+        long bits = Double.doubleToRawLongBits(imm);
+        // lower 48 bits are cleared
+        if ((bits & NumUtil.getNbitNumberLong(48)) != 0) {
+            return false;
+        }
+        // bits[61..54] are all set or all cleared.
+        long pattern = (bits >> 54) & NumUtil.getNbitNumberLong(7);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberLong(7)) {
+            return false;
+        }
+        // bits[62] and bits[61] are opposites.
+        return ((bits ^ (bits << 1)) & (1L << 62)) != 0;
+    }
+
+    private static int getFloatImmediate(float imm) {
+        assert isFloatImmediate(imm);
+        // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int repr = Float.floatToRawIntBits(imm);
+        int a = (repr >>> 31) << 7;
+        int b = ((repr >>> 29) & 0x1) << 6;
+        int cToH = (repr >>> 19) & NumUtil.getNbitNumberInt(6);
+        return (a | b | cToH) << FpImmOffset;
+    }
+
+    protected static boolean isFloatImmediate(float imm) {
+        // Valid values will have the form:
+        // aBbb.bbbc.defg.h000.0000.0000.0000.0000
+        int bits = Float.floatToRawIntBits(imm);
+        // lower 20 bits are cleared.
+        if ((bits & NumUtil.getNbitNumberInt(19)) != 0) {
+            return false;
+        }
+        // bits[29..25] are all set or all cleared
+        int pattern = (bits >> 25) & NumUtil.getNbitNumberInt(5);
+        if (pattern != 0 && pattern != NumUtil.getNbitNumberInt(5)) {
+            return false;
+        }
+        // bits[29] and bits[30] have to be opposite
+        return ((bits ^ (bits << 1)) & (1 << 30)) != 0;
+    }
+
+    /* Convert Floating-point Precision (5.7.4.1) */
+    /* Converts float to double and vice-versa */
+
+    /**
+     * Convert float to double and vice-versa.
+     *
+     * @param srcSize size of source register in bits.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvt(int srcSize, Register dst, Register src) {
+        if (srcSize == 32) {
+            fpDataProcessing1Source(dst, src, floatFromSize(srcSize), Instruction.FCVTDS);
+        } else {
+            fpDataProcessing1Source(dst, src, floatFromSize(srcSize), Instruction.FCVTSD);
+        }
+    }
+
+    /* Convert to Integer (5.7.4.2) */
+
+    /**
+     * Convert floating point to integer. Rounds towards zero.
+     *
+     * @param targetSize size of integer register. 32 or 64.
+     * @param srcSize size of floating point register. 32 or 64.
+     * @param dst general purpose register. May not be null, the zero-register or the stackpointer.
+     * @param src floating point register. May not be null.
+     */
+    public void fcvtzs(int targetSize, int srcSize, Register dst, Register src) {
+        assert !dst.equals(zr) && !dst.equals(sp);
+        assert src.getRegisterCategory().equals(SIMD);
+        fcvtCpuFpuInstruction(dst, src, generalFromSize(targetSize), floatFromSize(srcSize), Instruction.FCVTZS);
+    }
+
+    /* Convert from Integer (5.7.4.2) */
+    /**
+     * Converts integer to floating point. Uses rounding mode defined by FCPR.
+     *
+     * @param targetSize size of floating point register. 32 or 64.
+     * @param srcSize size of integer register. 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param src general purpose register. May not be null or the stackpointer.
+     */
+    public void scvtf(int targetSize, int srcSize, Register dst, Register src) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert !src.equals(sp);
+        fcvtCpuFpuInstruction(dst, src, floatFromSize(targetSize), generalFromSize(srcSize), Instruction.SCVTF);
+    }
+
+    private void fcvtCpuFpuInstruction(Register dst, Register src, InstructionType type1, InstructionType type2, Instruction instr) {
+        int instrEncoding = instr.encoding | FpConvertOp;
+        emitInt(type1.encoding | type2.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Round to Integral (5.7.5) */
+
+    /**
+     * Rounds floating-point to integral. Rounds towards zero.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    protected void frintz(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FRINTZ);
+    }
+
+    /* Floating-point Arithmetic (1 source) (5.7.6) */
+
+    /**
+     * dst = |src|.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fabs(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FABS);
+    }
+
+    /**
+     * dst = -neg.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fneg(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FNEG);
+    }
+
+    /**
+     * dst = Sqrt(src).
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src floating point register. May not be null.
+     */
+    public void fsqrt(int size, Register dst, Register src) {
+        fpDataProcessing1Source(dst, src, floatFromSize(size), Instruction.FSQRT);
+    }
+
+    private void fpDataProcessing1Source(Register dst, Register src, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp1SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src));
+    }
+
+    /* Floating-point Arithmetic (2 source) (5.7.7) */
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fadd(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FADD);
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fsub(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FSUB);
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fmul(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FMUL);
+    }
+
+    /**
+     * dst = src1 / src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fdiv(int size, Register dst, Register src1, Register src2) {
+        fpDataProcessing2Source(dst, src1, src2, floatFromSize(size), Instruction.FDIV);
+    }
+
+    private void fpDataProcessing2Source(Register dst, Register src1, Register src2, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp2SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2));
+    }
+
+    /* Floating-point Multiply-Add (5.7.9) */
+
+    /**
+     * dst = src1 * src2 + src3.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmadd(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(dst, src1, src2, src3, floatFromSize(size), Instruction.FMADD);
+    }
+
+    /**
+     * dst = src3 - src1 * src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param src3 floating point register. May not be null.
+     */
+    protected void fmsub(int size, Register dst, Register src1, Register src2, Register src3) {
+        fpDataProcessing3Source(dst, src1, src2, src3, floatFromSize(size), Instruction.FMSUB);
+    }
+
+    private void fpDataProcessing3Source(Register dst, Register src1, Register src2, Register src3, InstructionType type, Instruction instr) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        assert src3.getRegisterCategory().equals(SIMD);
+        int instrEncoding = instr.encoding | Fp3SourceOp;
+        emitInt(type.encoding | instrEncoding | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
+    /* Floating-point Comparison (5.7.10) */
+
+    /**
+     * Compares src1 to src2.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fcmp(int size, Register src1, Register src2) {
+        fcmpInstruction(src1, src2, floatFromSize(size));
+    }
+
+    private void fcmpInstruction(Register src1, Register src2, InstructionType type) {
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        int instrEncoding = Instruction.FCMP.encoding | FpCmpOp;
+        emitInt(type.encoding | instrEncoding | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param uimm4 condition flags that are used if condition is false.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fccmp(int size, Register src1, Register src2, int uimm4, ConditionFlag condition) {
+        fConditionalCompareInstruction(src1, src2, uimm4, condition, floatFromSize(size));
+    }
+
+    private void fConditionalCompareInstruction(Register src1, Register src2, int uimm4, ConditionFlag condition, InstructionType type) {
+        assert NumUtil.isUnsignedNbit(4, uimm4);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | Instruction.FCCMP.encoding | uimm4 | condition.encoding << ConditionalConditionOffset | rs1(src1) | rs2(src2));
+    }
+
+    /**
+     * Compare register to 0.0 .
+     *
+     * @param size register size.
+     * @param src floating point register. May not be null.
+     */
+    public void fcmpZero(int size, Register src) {
+        fcmpZeroInstruction(src, floatFromSize(size));
+    }
+
+    private void fcmpZeroInstruction(Register src, InstructionType type) {
+        assert src.getRegisterCategory().equals(SIMD);
+        int instrEncoding = Instruction.FCMPZERO.encoding | FpCmpOp;
+        emitInt(type.encoding | instrEncoding | rs1(src));
+    }
+
+    /* Floating-point Conditional Select (5.7.11) */
+
+    /**
+     * Conditional select. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param dst floating point register. May not be null.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    protected void fcsel(int size, Register dst, Register src1, Register src2, ConditionFlag condition) {
+        fConditionalSelect(dst, src1, src2, condition, floatFromSize(size));
+    }
+
+    private void fConditionalSelect(Register dst, Register src1, Register src2, ConditionFlag condition, InstructionType type) {
+        assert dst.getRegisterCategory().equals(SIMD);
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        emitInt(type.encoding | Instruction.FCSEL.encoding | rd(dst) | rs1(src1) | rs2(src2) | condition.encoding << ConditionalConditionOffset);
+    }
+
+    /* Debug exceptions (5.9.1.2) */
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void hlt(int uimm16) {
+        exceptionInstruction(uimm16, Instruction.HLT);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param uimm16 Arbitrary 16-bit unsigned payload.
+     */
+    protected void brk(int uimm16) {
+        exceptionInstruction(uimm16, Instruction.BRK);
+    }
+
+    /* Architectural hints (5.9.4) */
+    public enum SystemHint {
+        NOP(0x0),
+        YIELD(0x1),
+        WFE(0x2),
+        WFI(0x3),
+        SEV(0x4),
+        SEVL(0x5);
+
+        private final int encoding;
+
+        private SystemHint(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Architectural hints.
+     *
+     * @param hint Can be any of the defined hints. May not be null.
+     */
+    protected void hint(SystemHint hint) {
+        emitInt(Instruction.HINT.encoding | hint.encoding << SystemImmediateOffset);
+    }
+
+    private void exceptionInstruction(int uimm16, Instruction instr) {
+        assert NumUtil.isUnsignedNbit(16, uimm16);
+        int instrEncoding = instr.encoding | ExceptionOp;
+        emitInt(instrEncoding | uimm16 << SystemImmediateOffset);
+    }
+
+    /**
+     * Clear Exclusive: clears the local record of the executing processor that an address has had a
+     * request for an exclusive access.
+     */
+    protected void clrex() {
+        emitInt(Instruction.CLREX.encoding);
+    }
+
+    /**
+     * Possible barrier definitions for Aarch64. LOAD_LOAD and LOAD_STORE map to the same underlying
+     * barrier.
+     *
+     * We only need synchronization across the inner shareable domain (see B2-90 in the Reference
+     * documentation).
+     */
+    public enum BarrierKind {
+        LOAD_LOAD(0x9, "ISHLD"),
+        LOAD_STORE(0x9, "ISHLD"),
+        STORE_STORE(0xA, "ISHST"),
+        ANY_ANY(0xB, "ISH");
+
+        public final int encoding;
+        public final String optionName;
+
+        private BarrierKind(int encoding, String optionName) {
+            this.encoding = encoding;
+            this.optionName = optionName;
+        }
+    }
+
+    /**
+     * Data Memory Barrier.
+     *
+     * @param barrierKind barrier that is issued. May not be null.
+     */
+    public void dmb(BarrierKind barrierKind) {
+        barrierInstruction(barrierKind, Instruction.DMB);
+    }
+
+    private void barrierInstruction(BarrierKind barrierKind, Instruction instr) {
+        int instrEncoding = instr.encoding | BarrierOp;
+        emitInt(instrEncoding | barrierKind.encoding << BarrierKindOffset);
+    }
+
+    // Artificial instructions for simulator. These instructions are illegal in the normal aarch64
+    // ISA,
+    // but have special meaning for the simulator
+
+    /**
+     * Branch and link register instruction with the target code being native, i.e. not aarch64.
+     *
+     * The simulator has to do extra work so needs to know the number of arguments (both gp and fp)
+     * as well as the type of the return value. See assembler_aarch64.hpp.
+     *
+     * @param reg general purpose register. May not be null, zero-register or stackpointer. Contains
+     *            address of target method.
+     * @param gpArgs number of general purpose arguments passed to the function. 4-bit unsigned.
+     * @param fpArgs number of floating point arguments passed to the function. 4-bit unsigned.
+     * @param returnType returnType of function. May not be null, or Kind.ILLEGAL.
+     */
+    public void blrNative(Register reg, int gpArgs, int fpArgs, JavaKind returnType) {
+        assert reg.getRegisterCategory().equals(CPU) && NumUtil.isUnsignedNbit(4, gpArgs) && NumUtil.isUnsignedNbit(4, fpArgs) && returnType != null;
+        emitInt(Instruction.BLR_NATIVE.encoding | reg.encoding | getReturnTypeEncoding(returnType) << 5 | fpArgs << 7 | gpArgs << 11);
+    }
+
+    private static int getReturnTypeEncoding(JavaKind returnType) {
+        // See assembler_aarch64.hpp for encoding details
+        switch (returnType) {
+            case Boolean:
+            case Byte:
+            case Short:
+            case Char:
+            case Int:
+            case Long:
+            case Object:
+                return 1;
+            case Float:
+                return 2;
+            case Double:
+                return 3;
+            case Void:
+            case Illegal:
+                // Void functions use a result of Kind.Illegal apparently
+                return 0;
+            default:
+                throw JVMCIError.shouldNotReachHere("Illegal kind");
+        }
+    }
+
+    /* Helper functions */
+    private static int rd(Register reg) {
+        return reg.encoding << RdOffset;
+    }
+
+    private static int rs1(Register reg) {
+        return reg.encoding << Rs1Offset;
+    }
+
+    private static int rs2(Register reg) {
+        return reg.encoding << Rs2Offset;
+    }
+
+    private static int rs3(Register reg) {
+        return reg.encoding << Rs3Offset;
+    }
+
+    private static int rt(Register reg) {
+        return reg.encoding << RtOffset;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.aarch64/src/com/oracle/graal/asm/aarch64/AArch64MacroAssembler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,1366 @@
+/*
+ * 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.asm.aarch64;
+
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.BASE_REGISTER_ONLY;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED;
+import static com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX;
+import static com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK;
+import static jdk.vm.ci.aarch64.AArch64.CPU;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import com.oracle.graal.asm.AbstractAddress;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.NumUtil;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+
+public class AArch64MacroAssembler extends AArch64Assembler {
+
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(r8), new ScratchRegister(r9)};
+
+    // Points to the next free scratch register
+    private int nextFreeScratchRegister = 0;
+
+    public AArch64MacroAssembler(TargetDescription target) {
+        super(target);
+    }
+
+    public class ScratchRegister implements AutoCloseable {
+        private final Register register;
+
+        public ScratchRegister(Register register) {
+            this.register = register;
+        }
+
+        public Register getRegister() {
+            return register;
+        }
+
+        public void close() {
+            assert nextFreeScratchRegister > 0 : "Close called too often";
+            nextFreeScratchRegister--;
+        }
+    }
+
+    public ScratchRegister getScratchRegister() {
+        return scratchRegister[nextFreeScratchRegister++];
+    }
+
+    /**
+     * Specifies what actions have to be taken to turn an arbitrary address of the form
+     * {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address.
+     */
+    public static class AddressGenerationPlan {
+        public final WorkPlan workPlan;
+        public final AArch64Address.AddressingMode addressingMode;
+        public final boolean needsScratch;
+
+        public enum WorkPlan {
+            /**
+             * Can be used as-is without extra work.
+             */
+            NO_WORK,
+            /**
+             * Add scaled displacement to index register.
+             */
+            ADD_TO_INDEX,
+            /**
+             * Add unscaled displacement to base register.
+             */
+            ADD_TO_BASE,
+        }
+
+        /**
+         * @param workPlan Work necessary to generate a valid address.
+         * @param addressingMode Addressing mode of generated address.
+         * @param needsScratch True if generating address needs a scatch register, false otherwise.
+         */
+        public AddressGenerationPlan(WorkPlan workPlan, AArch64Address.AddressingMode addressingMode, boolean needsScratch) {
+            this.workPlan = workPlan;
+            this.addressingMode = addressingMode;
+            this.needsScratch = needsScratch;
+        }
+    }
+
+    /**
+     * Generates an addressplan for an address of the form
+     * {@code base + displacement [+ index [<< log2(transferSize)]]} with the index register and
+     * scaling being optional.
+     *
+     * @param displacement an arbitrary displacement.
+     * @param hasIndexRegister true if the address uses an index register, false otherwise. non null
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AddressGenerationPlan that specifies the actions necessary to generate a valid
+     *         AArch64Address for the given parameters.
+     */
+    public static AddressGenerationPlan generateAddressPlan(long displacement, boolean hasIndexRegister, int transferSize) {
+        assert transferSize == 0 || transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        boolean indexScaled = transferSize != 0;
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        boolean displacementScalable = indexScaled && (displacement & (transferSize - 1)) == 0;
+        if (displacement == 0) {
+            // register offset without any work beforehand.
+            return new AddressGenerationPlan(NO_WORK, REGISTER_OFFSET, false);
+        } else {
+            if (hasIndexRegister) {
+                if (displacementScalable) {
+                    boolean needsScratch = !isArithmeticImmediate(scaledDisplacement);
+                    return new AddressGenerationPlan(ADD_TO_INDEX, REGISTER_OFFSET, needsScratch);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            } else {
+                if (NumUtil.isSignedNbit(9, displacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_UNSCALED, false);
+                } else if (displacementScalable && NumUtil.isUnsignedNbit(12, scaledDisplacement)) {
+                    return new AddressGenerationPlan(NO_WORK, IMMEDIATE_SCALED, false);
+                } else {
+                    boolean needsScratch = !isArithmeticImmediate(displacement);
+                    return new AddressGenerationPlan(ADD_TO_BASE, REGISTER_OFFSET, needsScratch);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns an AArch64Address pointing to
+     * {@code base + displacement + index << log2(transferSize)}.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param index general purpose register. May not be null or the stack pointer.
+     * @param signExtendIndex if true consider index register a word register that should be
+     *            sign-extended before being added.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be null
+     *            or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at
+     *         {@code base + displacement + index << log2(transferSize)}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register index, boolean signExtendIndex, int transferSize, Register additionalReg, boolean allowOverwrite) {
+        AddressGenerationPlan plan = generateAddressPlan(displacement, !index.equals(zr), transferSize);
+        assert allowOverwrite || !zr.equals(additionalReg) || plan.workPlan == NO_WORK;
+        assert !plan.needsScratch || !zr.equals(additionalReg);
+        int log2Scale = NumUtil.log2Ceil(transferSize);
+        long scaledDisplacement = displacement >> log2Scale;
+        Register newIndex = index;
+        Register newBase = base;
+        int immediate;
+        switch (plan.workPlan) {
+            case NO_WORK:
+                if (plan.addressingMode == IMMEDIATE_SCALED) {
+                    immediate = (int) scaledDisplacement;
+                } else {
+                    immediate = (int) displacement;
+                }
+                break;
+            case ADD_TO_INDEX:
+                newIndex = allowOverwrite ? index : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, scaledDisplacement);
+                    add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg);
+                } else {
+                    add(signExtendIndex ? 32 : 64, newIndex, index, (int) scaledDisplacement);
+                }
+                immediate = 0;
+                break;
+            case ADD_TO_BASE:
+                newBase = allowOverwrite ? base : additionalReg;
+                if (plan.needsScratch) {
+                    mov(additionalReg, displacement);
+                    add(64, newBase, base, additionalReg);
+                } else {
+                    add(64, newBase, base, (int) displacement);
+                }
+                immediate = 0;
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+        AArch64Address.AddressingMode addressingMode = plan.addressingMode;
+        ExtendType extendType = null;
+        if (addressingMode == REGISTER_OFFSET) {
+            if (newIndex.equals(zr)) {
+                addressingMode = BASE_REGISTER_ONLY;
+            } else if (signExtendIndex) {
+                addressingMode = EXTENDED_REGISTER_OFFSET;
+                extendType = ExtendType.SXTW;
+            }
+        }
+        return AArch64Address.createAddress(addressingMode, newBase, newIndex, immediate, transferSize != 0, extendType);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Specifies the memory
+     * transfer size to allow some optimizations when building the address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes.
+     * @param additionalReg additional register used either as a scratch register or as part of the
+     *            final address, depending on whether allowOverwrite is true or not. May not be
+     *            null, zero register or stackpointer.
+     * @param allowOverwrite if true allows to change value of base or index register to generate
+     *            address.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, Register additionalReg, int transferSize, boolean allowOverwrite) {
+        assert additionalReg.getRegisterCategory().equals(CPU);
+        return makeAddress(base, displacement, zr, /* sign-extend */false, transferSize, additionalReg, allowOverwrite);
+    }
+
+    /**
+     * Returns an AArch64Address pointing to {@code base + displacement}. Fails if address cannot be
+     * represented without overwriting base register or using a scratch register.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. If 0 no scaling is assumed. Can be 0, 1, 2, 4 or 8.
+     * @return AArch64Address pointing to memory at {@code base + displacement}.
+     */
+    public AArch64Address makeAddress(Register base, long displacement, int transferSize) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false);
+    }
+
+    /**
+     * Loads memory address into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param address address whose value is loaded into dst. May not be null,
+     *            {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_POST_INDEXED
+     *            POST_INDEXED} or
+     *            {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#IMMEDIATE_PRE_INDEXED
+     *            IMMEDIATE_PRE_INDEXED}
+     * @param transferSize the memory transfer size in bytes. The log2 of this specifies how much
+     *            the index register is scaled. Can be 1, 2, 4 or 8.
+     */
+    public void loadAddress(Register dst, AArch64Address address, int transferSize) {
+        assert transferSize == 1 || transferSize == 2 || transferSize == 4 || transferSize == 8;
+        assert dst.getRegisterCategory().equals(CPU);
+        int shiftAmt = NumUtil.log2Ceil(transferSize);
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+                int scaledImmediate = address.getImmediateRaw() << shiftAmt;
+                int lowerBits = scaledImmediate & NumUtil.getNbitNumberInt(12);
+                int higherBits = scaledImmediate & ~NumUtil.getNbitNumberInt(12);
+                boolean firstAdd = true;
+                if (lowerBits != 0) {
+                    add(64, dst, address.getBase(), lowerBits);
+                    firstAdd = false;
+                }
+                if (higherBits != 0) {
+                    Register src = firstAdd ? address.getBase() : dst;
+                    add(64, dst, src, higherBits);
+                }
+                break;
+            case IMMEDIATE_UNSCALED:
+                int immediate = address.getImmediateRaw();
+                add(64, dst, address.getBase(), immediate);
+                break;
+            case REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), ShiftType.LSL, address.isScaled() ? shiftAmt : 0);
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0);
+                break;
+            case PC_LITERAL:
+                super.adr(dst, address.getImmediateRaw());
+                break;
+            case BASE_REGISTER_ONLY:
+                movx(dst, address.getBase());
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public void movx(Register dst, Register src) {
+        mov(64, dst, src);
+    }
+
+    public void mov(int size, Register dst, Register src) {
+        if (dst.equals(src)) {
+            return;
+        }
+        if (dst.equals(sp) || src.equals(sp)) {
+            add(size, dst, src, 0);
+        } else {
+            or(size, dst, src, zr);
+        }
+    }
+
+    /**
+     * Generates a move 64-bit immediate code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param imm
+     */
+    public void forceMov(Register dst, long imm, boolean optimize) {
+        // We have to move all non zero parts of the immediate in 16-bit chunks
+        boolean firstMove = true;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (optimize && chunk == 0) {
+                continue;
+            }
+            if (firstMove) {
+                movz(64, dst, chunk, offset);
+                firstMove = false;
+            } else {
+                movk(64, dst, chunk, offset);
+            }
+        }
+        assert !firstMove;
+    }
+
+    public void forceMov(Register dst, long imm) {
+        forceMov(dst, imm, /* optimize */false);
+    }
+
+    /**
+     * Generates a move 64-bit immediate code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     */
+    public void forceMov(Register dst, int imm) {
+        forceMov(dst, imm & 0xFFFF_FFFFL);
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, long imm) {
+        assert dst.getRegisterCategory().equals(CPU);
+        if (imm == 0L) {
+            movx(dst, zr);
+        } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            or(64, dst, zr, imm);
+        } else if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            mov(dst, (int) imm);
+            sxt(64, 32, dst, dst);
+        } else {
+            forceMov(dst, imm, /* optimize move */true);
+        }
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     */
+    public void mov(Register dst, int imm) {
+        mov(dst, imm & 0xFFFF_FFFFL);
+    }
+
+    /**
+     * @return Number of instructions necessary to load immediate into register.
+     */
+    public static int nrInstructionsToMoveImmediate(long imm) {
+        if (imm == 0L || LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
+            return 1;
+        }
+        if (imm >> 32 == -1L && (int) imm < 0 && LogicalImmediateTable.isRepresentable((int) imm) != LogicalImmediateTable.Representable.NO) {
+            // If the higher 32-bit are 1s and the sign bit of the lower 32-bits is set *and* we can
+            // represent the lower 32 bits as a logical immediate we can create the lower 32-bit and
+            // then sign extend
+            // them. This allows us to cover immediates like ~1L with 2 instructions.
+            return 2;
+        }
+        int nrInstructions = 0;
+        for (int offset = 0; offset < 64; offset += 16) {
+            int part = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
+            if (part != 0) {
+                nrInstructions++;
+            }
+        }
+        return nrInstructions;
+    }
+
+    /**
+     * Loads a srcSize value from address into rt sign-extending it if necessary.
+     *
+     * @param targetSize size of target register in bits. Must be 32 or 64.
+     * @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to
+     *            targetSize.
+     * @param rt general purpose register. May not be null or stackpointer.
+     * @param address all addressing modes allowed. May not be null.
+     */
+    @Override
+    public void ldrs(int targetSize, int srcSize, Register rt, AArch64Address address) {
+        assert targetSize == 32 || targetSize == 64;
+        assert srcSize <= targetSize;
+        if (targetSize == srcSize) {
+            super.ldr(srcSize, rt, address);
+        } else {
+            super.ldrs(targetSize, srcSize, rt, address);
+        }
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param result general purpose register. May not be null or the stackpointer.
+     * @param trueValue general purpose register. May not be null or the stackpointer.
+     * @param falseValue general purpose register. May not be null or the stackpointer.
+     * @param cond any condition flag. May not be null.
+     */
+    public void cmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag cond) {
+        super.csel(size, result, trueValue, falseValue, cond);
+    }
+
+    /**
+     * Conditional set. dst = 1 if condition else 0.
+     *
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param condition any condition. May not be null.
+     */
+    public void cset(Register dst, ConditionFlag condition) {
+        super.csinc(32, dst, zr, zr, condition.negate());
+    }
+
+    /**
+     * dst = src1 + src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void add(int size, Register dst, Register src1, Register src2) {
+        super.add(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void adds(int size, Register dst, Register src1, Register src2) {
+        super.adds(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * dst = src1 - src2 and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void subs(int size, Register dst, Register src1, Register src2) {
+        super.subs(size, dst, src1, src2, getNopExtendType(size), 0);
+    }
+
+    /**
+     * Returns the ExtendType for the given size that corresponds to a no-op.
+     *
+     * I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX.
+     *
+     * @param size
+     */
+    private static ExtendType getNopExtendType(int size) {
+        if (size == 64) {
+            return ExtendType.UXTX;
+        } else if (size == 32) {
+            return ExtendType.UXTW;
+        } else {
+            throw JVMCIError.shouldNotReachHere("No-op ");
+        }
+    }
+
+    /**
+     * dst = src1 - src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void sub(int size, Register dst, Register src1, Register src2) {
+        super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void add(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.add(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = src1 + shiftType(src2, shiftAmt & (size-1)) and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     * @param shiftType any type but ROR.
+     * @param shiftAmt arbitrary shift amount.
+     */
+    @Override
+    public void sub(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sub(size, dst, src1, src2, shiftType, shift);
+    }
+
+    /**
+     * dst = -src1.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void neg(int size, Register dst, Register src) {
+        sub(size, dst, zr, src);
+    }
+
+    /**
+     * dst = src + immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void add(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            sub(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.add(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src + aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void adds(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            subs(size, dst, src, -immediate);
+        } else if (!(dst.equals(src) && immediate == 0)) {
+            super.adds(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - immediate.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param immediate arithmetic immediate
+     */
+    @Override
+    public void sub(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            add(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src - aimm and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or zero-register.
+     * @param immediate arithmetic immediate.
+     */
+    @Override
+    public void subs(int size, Register dst, Register src, int immediate) {
+        if (immediate < 0) {
+            adds(size, dst, src, -immediate);
+        } else if (!dst.equals(src) || immediate != 0) {
+            super.sub(size, dst, src, immediate);
+        }
+    }
+
+    /**
+     * dst = src1 * src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void mul(int size, Register dst, Register src1, Register src2) {
+        super.madd(size, dst, src1, src2, zr);
+    }
+
+    /**
+     * unsigned multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void umulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.umulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.umaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * signed multiply high. dst = (src1 * src2) >> size
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     */
+    public void smulh(int size, Register dst, Register src1, Register src2) {
+        assert size == 32 || size == 64;
+        if (size == 64) {
+            super.smulh(dst, src1, src2);
+        } else {
+            // xDst = wSrc1 * wSrc2
+            super.smaddl(dst, src1, src2, zr);
+            // xDst = xDst >> 32
+            lshr(64, dst, dst, 32);
+        }
+    }
+
+    /**
+     * dst = src1 % src2. Signed.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void rem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d if nd >= 0
+        // n % d = n - Ceil(n / d) * d else
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.sdiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * dst = src1 % src2. Unsigned.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param n numerator. General purpose register. May not be null or the stackpointer.
+     * @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
+     */
+    public void urem(int size, Register dst, Register n, Register d) {
+        // There is no irem or similar instruction. Instead we use the relation:
+        // n % d = n - Floor(n / d) * d
+        // Which is equivalent to n - TruncatingDivision(n, d) * d
+        super.udiv(size, dst, n, d);
+        super.msub(size, dst, dst, d, n);
+    }
+
+    /**
+     * @return True if immediate can be used directly for arithmetic instructions (add/sub), false
+     *         otherwise.
+     */
+    public static boolean isArithmeticImmediate(long imm) {
+        // If we have a negative immediate we just use the opposite operator. I.e.: x - (-5) == x +
+        // 5.
+        return NumUtil.isInt(Math.abs(imm)) && isAimm((int) Math.abs(imm));
+    }
+
+    /**
+     * @return True if immediate can be used directly with comparison instructions, false otherwise.
+     */
+    public static boolean isComparisonImmediate(long imm) {
+        return isArithmeticImmediate(imm);
+    }
+
+    /**
+     * @return True if immediate can be moved directly into a register, false otherwise.
+     */
+    public static boolean isMovableImmediate(long imm) {
+        // Moves allow a 16bit immediate value that can be shifted by multiples of 16.
+        // Positions of first, respectively last set bit.
+        int start = Long.numberOfTrailingZeros(imm);
+        int end = 64 - Long.numberOfLeadingZeros(imm);
+        int length = end - start;
+        if (length > 16) {
+            return false;
+        }
+        // We can shift the necessary part of the immediate (i.e. everything between the first and
+        // last set bit) by as much as 16 - length around to arrive at a valid shift amount
+        int tolerance = 16 - length;
+        int prevMultiple = NumUtil.roundDown(start, 16);
+        int nextMultiple = NumUtil.roundUp(start, 16);
+        return start - prevMultiple <= tolerance || nextMultiple - start <= tolerance;
+    }
+
+    /**
+     * dst = src << (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void shl(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, (size - shift) & (size - 1), size - 1 - shift);
+    }
+
+    /**
+     * dst = src1 << (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void shl(int size, Register dst, Register src, Register shift) {
+        super.lsl(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >>> (shiftAmt & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void lshr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.ubfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >>> (src2 & (size - 1)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void lshr(int size, Register dst, Register src, Register shift) {
+        super.lsr(size, dst, src, shift);
+    }
+
+    /**
+     * dst = src >> (shiftAmt & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     * @param shiftAmt amount by which src is shifted.
+     */
+    public void ashr(int size, Register dst, Register src, long shiftAmt) {
+        int shift = clampShiftAmt(size, shiftAmt);
+        super.sbfm(size, dst, src, shift, size - 1);
+    }
+
+    /**
+     * dst = src1 >> (src2 & log2(size)).
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     * @param shift general purpose register. May not be null or stackpointer.
+     */
+    public void ashr(int size, Register dst, Register src, Register shift) {
+        super.asr(size, dst, src, shift);
+    }
+
+    /**
+     * Clamps shiftAmt into range 0 <= shiftamt < size according to JLS.
+     *
+     * @param size size of operation.
+     * @param shiftAmt arbitrary shift amount.
+     * @return value between 0 and size - 1 inclusive that is equivalent to shiftAmt according to
+     *         JLS.
+     */
+    private static int clampShiftAmt(int size, long shiftAmt) {
+        return (int) (shiftAmt & (size - 1));
+    }
+
+    /**
+     * dst = src1 & src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void and(int size, Register dst, Register src1, Register src2) {
+        super.and(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 ^ src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void eor(int size, Register dst, Register src1, Register src2) {
+        super.eor(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src1 | src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src1 general purpose register. May not be null or stackpointer.
+     * @param src2 general purpose register. May not be null or stackpointer.
+     */
+    public void or(int size, Register dst, Register src1, Register src2) {
+        super.orr(size, dst, src1, src2, ShiftType.LSL, 0);
+    }
+
+    /**
+     * dst = src | bimm.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or zero-register.
+     * @param src general purpose register. May not be null or stack-pointer.
+     * @param bimm logical immediate. See {@link AArch64Assembler.LogicalImmediateTable} for exact
+     *            definition.
+     */
+    public void or(int size, Register dst, Register src, long bimm) {
+        super.orr(size, dst, src, bimm);
+    }
+
+    /**
+     * dst = ~src.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stackpointer.
+     * @param src general purpose register. May not be null or stackpointer.
+     */
+    public void not(int size, Register dst, Register src) {
+        super.orn(size, dst, zr, src, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Sign-extend value from src into dst.
+     *
+     * @param destSize destination register size. Has to be 32 or 64.
+     * @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize.
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param src general purpose register. May not be null, stackpointer or zero-register.
+     */
+    public void sxt(int destSize, int srcSize, Register dst, Register src) {
+        assert (destSize == 32 || destSize == 64) && srcSize < destSize;
+        assert srcSize == 8 || srcSize == 16 || srcSize == 32;
+        int[] srcSizeValues = {7, 15, 31};
+        super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]);
+    }
+
+    /**
+     * dst = src if condition else -src.
+     *
+     * @param size register size. Must be 32 or 64.
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src general purpose register. May not be null or the stackpointer.
+     * @param condition any condition except AV or NV. May not be null.
+     */
+    public void csneg(int size, Register dst, Register src, ConditionFlag condition) {
+        super.csneg(size, dst, src, src, condition.negate());
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 64-bit instructions.
+     */
+    public static boolean isLogicalImmediate(long imm) {
+        return LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO;
+    }
+
+    /**
+     * @return True if the immediate can be used directly for logical 32-bit instructions.
+     */
+    public static boolean isLogicalImmediate(int imm) {
+        return LogicalImmediateTable.isRepresentable(imm) == LogicalImmediateTable.Representable.YES;
+    }
+
+    /* Float instructions */
+
+    /**
+     * Moves integer to float, float to integer, or float to float. Does not support integer to
+     * integer moves.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer or zero register. Cannot be null in any case.
+     * @param src Either floating-point or general-purpose register. If general-purpose register may
+     *            not be stackpointer. Cannot be null in any case.
+     */
+    @Override
+    public void fmov(int size, Register dst, Register src) {
+        assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)) : "src and dst cannot both be integer registers.";
+        if (dst.equals(src)) {
+            return;
+        }
+        if (dst.getRegisterCategory().equals(CPU)) {
+            super.fmovFpu2Cpu(size, dst, src);
+        } else if (src.getRegisterCategory().equals(CPU)) {
+            super.fmovCpu2Fpu(size, dst, src);
+        } else {
+            super.fmov(size, dst, src);
+        }
+    }
+
+    /**
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating point register. May not be null.
+     * @param imm immediate that is loaded into dst. If size is 32 only float immediates can be
+     *            loaded, i.e. (float) imm == imm must be true. In all cases
+     *            {@code isFloatImmediate}, respectively {@code #isDoubleImmediate} must be true
+     *            depending on size.
+     */
+    @Override
+    public void fmov(int size, Register dst, double imm) {
+        if (imm == 0.0) {
+            assert Double.doubleToRawLongBits(imm) == 0L : "-0.0 is no valid immediate.";
+            super.fmovCpu2Fpu(size, dst, zr);
+        } else {
+            super.fmov(size, dst, imm);
+        }
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isDoubleImmediate(double imm) {
+        return Double.doubleToRawLongBits(imm) == 0L || AArch64Assembler.isDoubleImmediate(imm);
+    }
+
+    /**
+     *
+     * @return true if immediate can be loaded directly into floating-point register, false
+     *         otherwise.
+     */
+    public static boolean isFloatImmediate(float imm) {
+        return Float.floatToRawIntBits(imm) == 0 || AArch64Assembler.isFloatImmediate(imm);
+    }
+
+    /**
+     * Conditional move. dst = src1 if condition else src2.
+     *
+     * @param size register size.
+     * @param result floating point register. May not be null.
+     * @param trueValue floating point register. May not be null.
+     * @param falseValue floating point register. May not be null.
+     * @param condition every condition allowed. May not be null.
+     */
+    public void fcmov(int size, Register result, Register trueValue, Register falseValue, ConditionFlag condition) {
+        super.fcsel(size, result, trueValue, falseValue, condition);
+    }
+
+    /**
+     * dst = src1 % src2.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst floating-point register. May not be null.
+     * @param n numerator. Floating-point register. May not be null.
+     * @param d denominator. Floating-point register. May not be null.
+     */
+    public void frem(int size, Register dst, Register n, Register d) {
+        // There is no frem instruction, instead we compute the remainder using the relation:
+        // rem = n - Truncating(n / d) * d
+        super.fdiv(size, dst, n, d);
+        super.frintz(size, dst, dst);
+        super.fmsub(size, dst, dst, d, n);
+    }
+
+    /* Branches */
+
+    /**
+     * Compares x and y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void cmp(int size, Register x, Register y) {
+        super.subs(size, zr, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * Compares x to y and sets condition flags.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it.
+     */
+    public void cmp(int size, Register x, int y) {
+        if (y < 0) {
+            super.adds(size, zr, x, -y);
+        } else {
+            super.subs(size, zr, x, y);
+        }
+    }
+
+    /**
+     * Sets condition flags according to result of x & y.
+     *
+     * @param size register size. Has to be 32 or 64.
+     * @param dst general purpose register. May not be null or stack-pointer.
+     * @param x general purpose register. May not be null or stackpointer.
+     * @param y general purpose register. May not be null or stackpointer.
+     */
+    public void ands(int size, Register dst, Register x, Register y) {
+        super.ands(size, dst, x, y, ShiftType.LSL, 0);
+    }
+
+    /**
+     * When patching up Labels we have to know what kind of code to generate.
+     */
+    public enum PatchLabelKind {
+        BRANCH_CONDITIONALLY(0x0),
+        BRANCH_UNCONDITIONALLY(0x1),
+        BRANCH_NONZERO(0x2),
+        BRANCH_ZERO(0x3),
+        JUMP_ADDRESS(0x4);
+
+        /**
+         * Offset by which additional information for branch conditionally, branch zero and branch
+         * non zero has to be shifted.
+         */
+        public static final int INFORMATION_OFFSET = 5;
+
+        public final int encoding;
+
+        private PatchLabelKind(int encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * @return PatchLabelKind with given encoding.
+         */
+        private static PatchLabelKind fromEncoding(int encoding) {
+            return values()[encoding & NumUtil.getNbitNumberInt(INFORMATION_OFFSET)];
+        }
+
+    }
+
+    /**
+     * Compare register and branch if non-zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbnz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbnz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_NONZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Compare register and branch if zero.
+     *
+     * @param size Instruction size in bits. Should be either 32 or 64.
+     * @param cmp general purpose register. May not be null, zero-register or stackpointer.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void cbz(int size, Register cmp, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.cbz(size, cmp, offset);
+        } else {
+            label.addPatchAt(position());
+            int regEncoding = cmp.encoding << (PatchLabelKind.INFORMATION_OFFSET + 1);
+            int sizeEncoding = (size == 64 ? 1 : 0) << PatchLabelKind.INFORMATION_OFFSET;
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_ZERO.encoding | regEncoding | sizeEncoding);
+        }
+    }
+
+    /**
+     * Branches to label if condition is true.
+     *
+     * @param condition any condition value allowed. Non null.
+     * @param label Can only handle 21-bit word-aligned offsets for now. May be unbound. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition, Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(condition, offset);
+        } else {
+            label.addPatchAt(position());
+            // Encode condition flag so that we know how to patch the instruction later
+            emitInt(PatchLabelKind.BRANCH_CONDITIONALLY.encoding | condition.encoding << PatchLabelKind.INFORMATION_OFFSET);
+        }
+    }
+
+    /**
+     * Branches if condition is true. Address of jump is patched up by HotSpot c++ code.
+     *
+     * @param condition any condition value allowed. Non null.
+     */
+    public void branchConditionally(ConditionFlag condition) {
+        // Correct offset is fixed up by HotSpot later.
+        super.b(condition, 0);
+    }
+
+    /**
+     * Jumps to label.
+     *
+     * param label Can only handle signed 28-bit offsets. May be unbound. Non null.
+     */
+    @Override
+    public void jmp(Label label) {
+        // TODO Handle case where offset is too large for a single jump instruction
+        if (label.isBound()) {
+            int offset = label.position() - position();
+            super.b(offset);
+        } else {
+            label.addPatchAt(position());
+            emitInt(PatchLabelKind.BRANCH_UNCONDITIONALLY.encoding);
+        }
+    }
+
+    /**
+     * Jump to address in dest.
+     *
+     * @param dest General purpose register. May not be null, zero-register or stackpointer.
+     */
+    public void jmp(Register dest) {
+        super.br(dest);
+    }
+
+    /**
+     * Immediate jump instruction fixed up by HotSpot c++ code.
+     */
+    public void jmp() {
+        // Offset has to be fixed up by c++ code.
+        super.b(0);
+    }
+
+    /**
+     *
+     * @return true if immediate offset can be used in a single branch instruction.
+     */
+    public static boolean isBranchImmediateOffset(long imm) {
+        return NumUtil.isSignedNbit(28, imm);
+    }
+
+    /* system instructions */
+
+    /**
+     * Exception codes used when calling hlt instruction.
+     */
+    public enum AArch64ExceptionCode {
+        NO_SWITCH_TARGET(0x0),
+        BREAKPOINT(0x1);
+
+        public final int encoding;
+
+        private AArch64ExceptionCode(int encoding) {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Halting mode software breakpoint: Enters halting mode debug state if enabled, else treated as
+     * UNALLOCATED instruction.
+     *
+     * @param exceptionCode exception code specifying why halt was called. Non null.
+     */
+    public void hlt(AArch64ExceptionCode exceptionCode) {
+        super.hlt(exceptionCode.encoding);
+    }
+
+    /**
+     * Monitor mode software breakpoint: exception routed to a debug monitor executing in a higher
+     * exception level.
+     *
+     * @param exceptionCode exception code specifying why break was called. Non null.
+     */
+    public void brk(AArch64ExceptionCode exceptionCode) {
+        super.brk(exceptionCode.encoding);
+    }
+
+    public void pause() {
+        throw JVMCIError.unimplemented();
+    }
+
+    /**
+     * Executes no-op instruction. No registers or flags are updated, except for PC.
+     */
+    public void nop() {
+        super.hint(SystemHint.NOP);
+    }
+
+    /**
+     * Same as {@link #nop()}.
+     */
+    @Override
+    public void ensureUniquePC() {
+        nop();
+    }
+
+    /**
+     * Aligns PC.
+     *
+     * @param modulus Has to be positive multiple of 4.
+     */
+    @Override
+    public void align(int modulus) {
+        assert modulus > 0 && (modulus & 0x3) == 0 : "Modulus has to be a positive multiple of 4.";
+        if (position() % modulus == 0) {
+            return;
+        }
+        int offset = modulus - position() % modulus;
+        for (int i = 0; i < offset; i += 4) {
+            nop();
+        }
+    }
+
+    /**
+     * Patches jump targets when label gets bound.
+     */
+    @Override
+    protected void patchJumpTarget(int branch, int jumpTarget) {
+        int instruction = getInt(branch);
+        int branchOffset = jumpTarget - branch;
+        PatchLabelKind type = PatchLabelKind.fromEncoding(instruction);
+        switch (type) {
+            case BRANCH_CONDITIONALLY:
+                ConditionFlag cf = ConditionFlag.fromEncoding(instruction >>> PatchLabelKind.INFORMATION_OFFSET);
+                super.b(cf, branchOffset, /* pos */branch);
+                break;
+            case BRANCH_UNCONDITIONALLY:
+                super.b(branchOffset, /* pos */branch);
+                break;
+            case JUMP_ADDRESS:
+                emitInt(jumpTarget, /* pos */branch);
+                break;
+            case BRANCH_NONZERO:
+            case BRANCH_ZERO:
+                int information = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
+                int sizeEncoding = information & 1;
+                int regEncoding = information >>> 1;
+                Register reg = AArch64.cpuRegisters[regEncoding];
+                // 1 => 64; 0 => 32
+                int size = sizeEncoding * 32 + 32;
+                switch (type) {
+                    case BRANCH_NONZERO:
+                        super.cbnz(size, reg, branchOffset, /* pos */branch);
+                        break;
+                    case BRANCH_ZERO:
+                        super.cbz(size, reg, branchOffset, /* pos */branch);
+                        break;
+                }
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Generates an address of the form {@code base + displacement}.
+     *
+     * Does not change base register to fulfil this requirement. Will fail if displacement cannot be
+     * represented directly as address.
+     *
+     * @param base general purpose register. May not be null or the zero register.
+     * @param displacement arbitrary displacement added to base.
+     * @return AArch64Address referencing memory at {@code base + displacement}.
+     */
+    @Override
+    public AArch64Address makeAddress(Register base, int displacement) {
+        return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false);
+    }
+
+    @Override
+    public AbstractAddress getPlaceholder() {
+        return AArch64Address.PLACEHOLDER;
+    }
+}
--- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,7 +36,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCIBackend;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import org.junit.Assert;
 
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/NumUtil.java	Tue Jan 05 16:42:05 2016 -0800
@@ -113,4 +113,74 @@
     public static long roundUp(long number, long mod) {
         return ((number + mod - 1L) / mod) * mod;
     }
+
+    public static int roundDown(int number, int mod) {
+        return number / mod * mod;
+    }
+
+    public static long roundDown(long number, long mod) {
+        return number / mod * mod;
+    }
+
+    public static int log2Ceil(int val) {
+        int x = 1;
+        int log2 = 0;
+        while (x < val) {
+            log2++;
+            x *= 2;
+        }
+        return log2;
+    }
+
+    public static boolean isUnsignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        return 32 - Integer.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isUnsignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        return 64 - Long.numberOfLeadingZeros(value) <= n;
+    }
+
+    public static boolean isSignedNbit(int n, int value) {
+        assert n > 0 && n < 32;
+        int min = -(1 << (n - 1));
+        int max = (1 << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    public static boolean isSignedNbit(int n, long value) {
+        assert n > 0 && n < 64;
+        long min = -(1L << (n - 1));
+        long max = (1L << (n - 1)) - 1;
+        return value >= min && value <= max;
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static int getNbitNumberInt(int n) {
+        assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n;
+        if (n < 32) {
+            return (1 << n) - 1;
+        } else {
+            return 0xFFFFFFFF;
+        }
+    }
+
+    /**
+     *
+     * @param n Number of bits that should be set to 1. Must be between 0 and 64 (inclusive).
+     * @return A number with n bits set to 1.
+     */
+    public static long getNbitNumberLong(int n) {
+        assert n >= 0 && n <= 64;
+        if (n < 64) {
+            return (1L << n) - 1;
+        } else {
+            return 0xFFFFFFFFFFFFFFFFL;
+        }
+    }
 }
--- a/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.code/src/com/oracle/graal/code/HexCodeFileDisassemblerProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -39,7 +39,8 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.service.ServiceProvider;
+
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64AddressLowering.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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.compiler.aarch64;
+
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.memory.address.AddressNode;
+import com.oracle.graal.phases.common.AddressLoweringPhase.AddressLowering;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class AArch64AddressLowering extends AddressLowering {
+
+    private final CodeCacheProvider codeCache;
+
+    public AArch64AddressLowering(CodeCacheProvider codeCache) {
+        this.codeCache = codeCache;
+    }
+
+    @Override
+    public AddressNode lower(ValueNode address) {
+        return lower(address, null);
+    }
+
+    @Override
+    public AddressNode lower(ValueNode base, ValueNode offset) {
+        asImmediate(base);
+        throw JVMCIError.unimplemented();
+    }
+
+    private JavaConstant asImmediate(ValueNode value) {
+        JavaConstant c = value.asJavaConstant();
+        if (c != null && c.getJavaKind().isNumericInteger() && !codeCache.needsDataPatch(c)) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64ArithmeticLIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
+import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.calc.FloatConvert;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticOp;
+import com.oracle.graal.lir.aarch64.AArch64BitManipulationOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.LoadOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.StoreConstantOp;
+import com.oracle.graal.lir.aarch64.AArch64Move.StoreOp;
+import com.oracle.graal.lir.aarch64.AArch64ReinterpretOp;
+import com.oracle.graal.lir.aarch64.AArch64SignExtendOp;
+import com.oracle.graal.lir.gen.ArithmeticLIRGenerator;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool {
+
+    @Override
+    public AArch64LIRGenerator getLIRGen() {
+        return (AArch64LIRGenerator) super.getLIRGen();
+    }
+
+    @Override
+    protected boolean isNumericInteger(PlatformKind kind) {
+        return ((AArch64Kind) kind).isInteger();
+    }
+
+    @Override
+    protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.ADDS : AArch64ArithmeticOp.ADD;
+            return emitBinary(resultKind, op, true, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FADD, true, a, b);
+        }
+    }
+
+    @Override
+    protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
+        if (isNumericInteger(a.getPlatformKind())) {
+            AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.SUBS : AArch64ArithmeticOp.SUB;
+            return emitBinary(resultKind, op, false, a, b);
+        } else {
+            assert !setFlags : "Cannot set flags on floating point arithmetic";
+            return emitBinary(resultKind, AArch64ArithmeticOp.FSUB, false, a, b);
+        }
+    }
+
+    @Override
+    public Value emitMul(Value a, Value b, boolean setFlags) {
+        // TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list
+        assert !setFlags : "Set flags on multiplication is not supported";
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b);
+    }
+
+    @Override
+    public Value emitMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitUMulHigh(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UMULH, true, a, b);
+    }
+
+    @Override
+    public Value emitDiv(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.DIV, AArch64ArithmeticOp.FDIV), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitRem(Value a, Value b, LIRFrameState state) {
+        return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.REM, AArch64ArithmeticOp.FREM), false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UDIV, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitURem(Value a, Value b, LIRFrameState state) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UREM, false, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+    }
+
+    @Override
+    public Value emitAnd(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.AND, true, a, b);
+    }
+
+    @Override
+    public Value emitOr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.OR, true, a, b);
+    }
+
+    @Override
+    public Value emitXor(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.XOR, true, a, b);
+    }
+
+    @Override
+    public Value emitShl(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SHL, false, a, b);
+    }
+
+    @Override
+    public Value emitShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ASHR, false, a, b);
+    }
+
+    @Override
+    public Value emitUShr(Value a, Value b) {
+        assert isNumericInteger(a.getPlatformKind());
+        return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.LSHR, false, a, b);
+    }
+
+    @Override
+    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
+        PlatformKind resultPlatformKind = getFloatConvertResultKind(op);
+        LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind);
+        Variable result = getLIRGen().newVariable(resultLirKind);
+        getLIRGen().append(new AArch64FloatConvertOp(op, result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    private static PlatformKind getFloatConvertResultKind(FloatConvert op) {
+        switch (op) {
+            case F2I:
+            case D2I:
+                return AArch64Kind.DWORD;
+            case F2L:
+            case D2L:
+                return AArch64Kind.QWORD;
+            case I2F:
+            case L2F:
+            case D2F:
+                return AArch64Kind.SINGLE;
+            case I2D:
+            case L2D:
+            case F2D:
+                return AArch64Kind.DOUBLE;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitReinterpret(LIRKind to, Value inputVal) {
+        LIRKind from = inputVal.getLIRKind();
+        if (to.equals(from)) {
+            return inputVal;
+        }
+        Variable result = getLIRGen().newVariable(to);
+        getLIRGen().append(new AArch64ReinterpretOp(result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    @Override
+    public Value emitNarrow(Value inputVal, int bits) {
+        assert inputVal.getPlatformKind() == AArch64Kind.QWORD && bits == 32 : "Can only convert from long to int";
+        LIRKind resultKind = getResultLirKind(bits, inputVal);
+        long mask = NumUtil.getNbitNumberLong(bits);
+        Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+        return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+    }
+
+    @Override
+    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        assert isNumericInteger(inputVal.getPlatformKind());
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        long mask = NumUtil.getNbitNumberLong(fromBits);
+        Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
+        return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
+    }
+
+    @Override
+    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
+        assert fromBits <= toBits && (toBits == 32 || toBits == 64);
+        if (fromBits == toBits) {
+            return inputVal;
+        }
+        LIRKind resultKind = getResultLirKind(toBits, inputVal);
+        Variable result = getLIRGen().newVariable(resultKind);
+        getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal)));
+        return result;
+    }
+
+    private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) {
+        if (resultBitSize == 64) {
+            return LIRKind.combine(inputValues).changeType(QWORD);
+        } else {
+            assert resultBitSize == 32;
+            return LIRKind.combine(inputValues).changeType(DWORD);
+        }
+    }
+
+    protected Variable emitBinary(LIRKind resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b) {
+        Variable result = getLIRGen().newVariable(resultKind);
+        if (isValidBinaryConstant(op, b)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(a), asJavaConstant(b));
+        } else if (commutative && isValidBinaryConstant(op, a)) {
+            emitBinaryConst(result, op, getLIRGen().asAllocatable(b), asJavaConstant(a));
+        } else {
+            emitBinaryVar(result, op, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b));
+        }
+        return result;
+    }
+
+    private void emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b) {
+        AllocatableValue x = moveSp(a);
+        AllocatableValue y = moveSp(b);
+        switch (op) {
+            case FREM:
+            case REM:
+            case UREM:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryCompositeOp(op, result, x, y));
+                break;
+            default:
+                getLIRGen().append(new AArch64ArithmeticOp.BinaryOp(op, result, x, y));
+                break;
+        }
+    }
+
+    private void emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b) {
+        AllocatableValue x = moveSp(a);
+        getLIRGen().append(new AArch64ArithmeticOp.BinaryConstOp(op, result, x, b));
+    }
+
+    private static boolean isValidBinaryConstant(AArch64ArithmeticOp op, Value val) {
+        if (!isJavaConstant(val)) {
+            return false;
+        }
+        JavaConstant constValue = asJavaConstant(val);
+        switch (op.category) {
+            case LOGICAL:
+                return isLogicalConstant(constValue);
+            case ARITHMETIC:
+                return isArithmeticConstant(constValue);
+            case SHIFT:
+                assert constValue.asLong() >= 0 && constValue.asLong() < val.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+                return true;
+            case NONE:
+                return false;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    private static boolean isLogicalConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asInt());
+            case Long:
+                return AArch64MacroAssembler.isLogicalImmediate(constValue.asLong());
+            default:
+                return false;
+        }
+    }
+
+    protected static boolean isArithmeticConstant(JavaConstant constValue) {
+        switch (constValue.getJavaKind()) {
+            case Int:
+            case Long:
+                return AArch64MacroAssembler.isArithmeticImmediate(constValue.asLong());
+            case Object:
+                return constValue.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public Value emitNegate(Value inputVal) {
+        return emitUnary(getOpCode(inputVal, AArch64ArithmeticOp.NEG, AArch64ArithmeticOp.FNEG), inputVal);
+    }
+
+    @Override
+    public Value emitNot(Value input) {
+        assert isNumericInteger(input.getPlatformKind());
+        return emitUnary(AArch64ArithmeticOp.NOT, input);
+    }
+
+    @Override
+    public Value emitMathAbs(Value input) {
+        return emitUnary(getOpCode(input, AArch64ArithmeticOp.ABS, AArch64ArithmeticOp.FABS), input);
+    }
+
+    @Override
+    public Value emitMathSqrt(Value input) {
+        assert input.getPlatformKind() == AArch64Kind.DOUBLE;
+        return emitUnary(AArch64ArithmeticOp.SQRT, input);
+    }
+
+    @Override
+    public Value emitBitScanForward(Value inputVal) {
+        return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal);
+    }
+
+    @Override
+    public Value emitBitCount(Value operand) {
+        throw JVMCIError.unimplemented("AArch64 ISA does not offer way to implement this more efficiently " + "than a simple Java algorithm.");
+    }
+
+    @Override
+    public Value emitBitScanReverse(Value inputVal) {
+        // TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node
+        // for that though
+        return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSR, inputVal);
+    }
+
+    private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) {
+        assert isNumericInteger(inputVal.getPlatformKind());
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64BitManipulationOp(op, result, input));
+        return result;
+    }
+
+    private Variable emitUnary(AArch64ArithmeticOp op, Value inputVal) {
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
+        getLIRGen().append(new AArch64ArithmeticOp.UnaryOp(op, result, input));
+        return result;
+    }
+
+    /**
+     * If val denotes the stackpointer, move it to another location. This is necessary since most
+     * ops cannot handle the stackpointer as input or output.
+     */
+    private AllocatableValue moveSp(AllocatableValue val) {
+        if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) {
+            assert val.getPlatformKind() == AArch64Kind.QWORD : "Stackpointer must be long";
+            return getLIRGen().emitMove(val);
+        }
+        return val;
+    }
+
+    /**
+     * Returns the opcode depending on the platform kind of val.
+     */
+    private AArch64ArithmeticOp getOpCode(Value val, AArch64ArithmeticOp intOp, AArch64ArithmeticOp floatOp) {
+        return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp;
+    }
+
+    @Override
+    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
+        AArch64AddressValue loadAddress = getLIRGen().asAddressValue(address);
+        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
+        getLIRGen().append(new LoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
+        return result;
+    }
+
+    @Override
+    public void emitStore(LIRKind lirKind, Value address, Value inputVal, LIRFrameState state) {
+        AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address);
+        AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
+
+        if (isJavaConstant(inputVal) && kind.isInteger()) {
+            JavaConstant c = asJavaConstant(inputVal);
+            if (c.isDefaultForKind()) {
+                // We can load 0 directly into integer registers
+                getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state));
+                return;
+            }
+        }
+        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
+        getLIRGen().append(new StoreOp(kind, storeAddress, input, state));
+    }
+
+    public Value emitMathLog(Value input, boolean base10) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathCos(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathSin(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitMathTan(Value input) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitCountLeadingZeros(Value value) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public Value emitCountTrailingZeros(Value value) {
+        throw JVMCIError.unimplemented();
+    }
+
+    public void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right) {
+        throw JVMCIError.unimplemented();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64FloatConvertOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,81 @@
+/*
+ * 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.compiler.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.calc.FloatConvert;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public final class AArch64FloatConvertOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64FloatConvertOp> TYPE = LIRInstructionClass.create(AArch64FloatConvertOp.class);
+
+    private final FloatConvert op;
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    protected AArch64FloatConvertOp(FloatConvert op, AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        this.op = op;
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        int fromSize = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        int toSize = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        switch (op) {
+            case F2I:
+            case D2I:
+            case F2L:
+            case D2L:
+                masm.fcvtzs(toSize, fromSize, result, input);
+                break;
+            case I2F:
+            case I2D:
+            case L2F:
+            case L2D:
+                masm.scvtf(toSize, fromSize, result, input);
+                break;
+            case D2F:
+            case F2D:
+                masm.fcvt(fromSize, result, input);
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64LIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64Assembler.ConditionFlag;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.compiler.common.spi.LIRKindTool;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRValueUtil;
+import com.oracle.graal.lir.LabelRef;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.SwitchStrategy;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticOp;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.aarch64.AArch64Compare;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow.BranchOp;
+import com.oracle.graal.lir.aarch64.AArch64ControlFlow.CondMoveOp;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.aarch64.AArch64Move;
+import com.oracle.graal.lir.aarch64.AArch64Move.CompareAndSwap;
+import com.oracle.graal.lir.aarch64.AArch64Move.MembarOp;
+import com.oracle.graal.lir.aarch64.AArch64PauseOp;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGenerator;
+import com.oracle.graal.phases.util.Providers;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public abstract class AArch64LIRGenerator extends LIRGenerator {
+
+    @SuppressWarnings("unused") private final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public static final class ConstantTableBaseProvider {
+        // private Variable constantTableBase;
+        @SuppressWarnings("unused") private boolean useConstantTableBase = false;
+
+        public Variable getConstantTableBase() {
+            useConstantTableBase = true;
+            // return constantTableBase;
+            return null;
+        }
+    }
+
+    public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, CallingConvention cc,
+                    LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, cc, lirGenRes);
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    /**
+     * 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 static final boolean canStoreConstant(JavaConstant c) {
+        // Our own code never calls this since we can't make a definite statement about whether or
+        // not we can inline a constant without knowing what kind of operation we execute. Let's be
+        // optimistic here and fix up mistakes later.
+        return true;
+    }
+
+    /**
+     * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
+     */
+    @Override
+    public LIRKind toRegisterKind(LIRKind kind) {
+        switch ((AArch64Kind) kind.getPlatformKind()) {
+            case BYTE:
+            case WORD:
+                return kind.changeType(AMD64Kind.DWORD);
+            default:
+                return kind;
+        }
+    }
+
+    @Override
+    public void emitNullCheck(Value address, LIRFrameState state) {
+        append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
+    }
+
+    @Override
+    public Variable emitAddress(AllocatableValue stackslot) {
+        Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
+        append(new AArch64Move.StackLoadAddressOp(result, stackslot));
+        return result;
+    }
+
+    public AArch64AddressValue asAddressValue(Value address) {
+        if (address instanceof AArch64AddressValue) {
+            return (AArch64AddressValue) address;
+        } else {
+            return new AArch64AddressValue(address.getLIRKind(), asAllocatable(address), Value.ILLEGAL, 0, false, AddressingMode.BASE_REGISTER_ONLY);
+        }
+    }
+
+    @Override
+    public void emitMove(AllocatableValue dst, Value src) {
+        append(createMove(dst, src));
+    }
+
+    @Override
+    public void emitMoveConstant(AllocatableValue dst, Constant src) {
+        append(createMoveConstant(dst, (JavaConstant) src));
+    }
+
+    /**
+     * Moves src to dst.
+     *
+     * If src is AArch64AddressValue the address value is loaded into dst, not the value pointed to
+     * by address. All valid combinations of src and dst values are supported, except StackSlot to
+     * StackSlot.
+     *
+     * @param dst Value stored on stack or in register. Non null.
+     * @param src Arbitrary input value. Non null.
+     * @return AArch64LIRInstruction representing the move. Non null.
+     */
+    protected AArch64LIRInstruction createMove(AllocatableValue dst, Value src) {
+        if (src instanceof AArch64AddressValue) {
+            return new AArch64Move.LoadAddressOp(dst, (AArch64AddressValue) src);
+        } else if (isStackSlot(dst)) {
+            return new AArch64Move.MoveToStackOp(dst, asAllocatable(src));
+        } else {
+            return new AArch64Move.MoveToRegOp(dst, asAllocatable(src));
+        }
+    }
+
+    protected AArch64LIRInstruction createMoveConstant(AllocatableValue dst, JavaConstant src) {
+        if (isStackSlotValue(dst)) {
+            // constant -> stack is not possible so we need a scratch register in between.
+            Variable tmp = newVariable(dst.getLIRKind());
+            append(new AArch64Move.MoveFromConstOp(tmp, src));
+            return new AArch64Move.MoveToStackOp(dst, tmp);
+        } else {
+            return new AArch64Move.MoveFromConstOp(dst, src);
+        }
+    }
+
+    @Override
+    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+        AArch64AddressValue addressValue = convertToBaseRegisterOnlyAddress(asAddressValue(address));
+        Variable result = newVariable(trueValue.getLIRKind());
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new CompareAndSwap(result, loadNonCompareConst(expectedValue), loadReg(newValue), addressValue, scratch));
+        return result;
+    }
+
+    /**
+     * Converts an arbitrary address to a BASE_REGISTER_ONLY form. This is useful since several
+     * instructions (e.g. load-acquire/store-release) are limited to this addressing mode.
+     *
+     * @return An address using the
+     *         {@link com.oracle.graal.asm.aarch64.AArch64Address.AddressingMode#BASE_REGISTER_ONLY}
+     *         addressingmode, pointing to the same location as address.
+     */
+    private AArch64AddressValue convertToBaseRegisterOnlyAddress(AArch64AddressValue address) {
+        AllocatableValue base = address.getBase();
+        AllocatableValue index = address.getOffset();
+        int immediate = address.getImmediate();
+        int shiftAmt;
+        if (address.isScaled()) {
+            shiftAmt = NumUtil.log2Ceil(address.getPlatformKind().getSizeInBytes() * Byte.SIZE);
+        } else {
+            shiftAmt = 0;
+        }
+        switch (address.getAddressingMode()) {
+            case IMMEDIATE_SCALED:
+            case IMMEDIATE_UNSCALED:
+                JavaConstant constVal = JavaConstant.forInt(immediate << shiftAmt);
+                ConstantValue constValue = new ConstantValue(LIRKind.value(AArch64Kind.WORD), constVal);
+                base = asAllocatable(getArithmetic().emitAdd(base, constValue, false));
+                break;
+            case REGISTER_OFFSET:
+                append(new AArch64ArithmeticOp.ExtendedAddShiftOp(base, base, index, AArch64Assembler.ExtendType.UXTX, shiftAmt));
+                break;
+            case EXTENDED_REGISTER_OFFSET:
+                append(new AArch64ArithmeticOp.ExtendedAddShiftOp(base, base, index, AArch64Assembler.ExtendType.SXTW, shiftAmt));
+                break;
+            case BASE_REGISTER_ONLY:
+                // nothing to do.
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+        return new AArch64AddressValue(address.getLIRKind(), base, Value.ILLEGAL, 0, false, AArch64Address.AddressingMode.BASE_REGISTER_ONLY);
+    }
+
+    @Override
+    public void emitData(AllocatableValue dst, byte[] data) {
+        append(new AArch64Move.LoadDataOp(dst, data));
+    }
+
+    @Override
+    public void emitMembar(int barriers) {
+        int necessaryBarriers = target().arch.requiredBarriers(barriers);
+        if (target().isMP && necessaryBarriers != 0) {
+            append(new MembarOp(necessaryBarriers));
+        }
+    }
+
+    @Override
+    public void emitJump(LabelRef label) {
+        assert label != null;
+        append(new StandardOp.JumpOp(label));
+    }
+
+    @Override
+    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) {
+        append(new AArch64ControlFlow.BranchOp(AArch64Assembler.ConditionFlag.VS, overflow, noOverflow, overflowProbability));
+    }
+
+    /**
+     * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueDestination destination if left & right == 0. Non null.
+     * @param falseDestination destination if left & right != 0. Non null
+     * @param trueSuccessorProbability hoistoric probability that comparison is true
+     */
+    @Override
+    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), AArch64ArithmeticOp.ANDS, true, left, right);
+        append(new AArch64ControlFlow.BranchOp(AArch64Assembler.ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability));
+    }
+
+    /**
+     * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else
+     * falseValue.
+     *
+     * @param left Arbitrary value. Has to have same type as right. Non null.
+     * @param right Arbitrary value. Has to have same type as left. Non null.
+     * @param cond condition that decides whether to move trueValue or falseValue into result. Non
+     *            null.
+     * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
+     *            not. Ignored for integer comparisons.
+     * @param trueValue arbitrary value same type as falseValue. Non null.
+     * @param falseValue arbitrary value same type as trueValue. Non null.
+     * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
+     *         null.
+     */
+    @Override
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        assert cmpKind == left.getPlatformKind() && cmpKind == right.getPlatformKind();
+        boolean mirrored = emitCompare(left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));
+        return result;
+    }
+
+    @Override
+    public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+                    double trueDestinationProbability) {
+        assert cmpKind == left.getPlatformKind() && cmpKind == right.getPlatformKind();
+        boolean mirrored = emitCompare(left, right, cond, unorderedIsTrue);
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
+        ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
+        append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
+    }
+
+    private static AArch64Assembler.ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
+        return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
+    }
+
+    /**
+     * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
+     * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly
+     * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'!
+     */
+    private static AArch64Assembler.ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) {
+        switch (cond) {
+            case LT:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.LT : AArch64Assembler.ConditionFlag.LO;
+            case LE:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.LE : AArch64Assembler.ConditionFlag.LS;
+            case GE:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.PL : AArch64Assembler.ConditionFlag.GE;
+            case GT:
+                return unorderedIsTrue ? AArch64Assembler.ConditionFlag.HI : AArch64Assembler.ConditionFlag.GT;
+            case EQ:
+                return AArch64Assembler.ConditionFlag.EQ;
+            case NE:
+                return AArch64Assembler.ConditionFlag.NE;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Takes a Condition and returns the correct Aarch64 specific ConditionFlag.
+     */
+    private static AArch64Assembler.ConditionFlag toIntConditionFlag(Condition cond) {
+        switch (cond) {
+            case EQ:
+                return AArch64Assembler.ConditionFlag.EQ;
+            case NE:
+                return AArch64Assembler.ConditionFlag.NE;
+            case LT:
+                return AArch64Assembler.ConditionFlag.LT;
+            case LE:
+                return AArch64Assembler.ConditionFlag.LE;
+            case GT:
+                return AArch64Assembler.ConditionFlag.GT;
+            case GE:
+                return AArch64Assembler.ConditionFlag.GE;
+            case AE:
+                return AArch64Assembler.ConditionFlag.HS;
+            case BE:
+                return AArch64Assembler.ConditionFlag.LS;
+            case AT:
+                return AArch64Assembler.ConditionFlag.HI;
+            case BT:
+                return AArch64Assembler.ConditionFlag.LO;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Emits a gpCompare instruction, possibly reordering the parameters.
+     *
+     * @param a the left operand of the comparison. Has to have same type as b. Non null.
+     * @param b the right operand of the comparison. Has to have same type as a. Non null.
+     * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done).
+     */
+    private boolean emitCompare(Value a, Value b, Condition condition, boolean unorderedIsTrue) {
+        boolean mirrored;
+        AllocatableValue left;
+        Value right;
+        if (((AArch64Kind) a.getPlatformKind()).isInteger()) {
+            if (LIRValueUtil.isVariable(b) || b instanceof RegisterValue) {
+                left = loadReg(b);
+                right = loadNonConst(a);
+                mirrored = true;
+            } else {
+                left = loadReg(a);
+                right = loadNonConst(b);
+                mirrored = true;
+            }
+            append(new AArch64Compare.CompareOp(left, asAllocatable(right)));
+        } else {
+            if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) {
+                left = loadReg(b);
+                right = a;
+                mirrored = true;
+            } else if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) {
+                left = loadReg(a);
+                right = b;
+                mirrored = false;
+            } else {
+                left = loadReg(a);
+                right = loadReg(b);
+                mirrored = false;
+            }
+            append(new AArch64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue));
+        }
+        return mirrored;
+    }
+
+    /**
+     * Checks whether value can be used directly with a gpCompare instruction. This is <b>not</b>
+     * the same as {@link AArch64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because
+     * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for
+     * floats.
+     *
+     * @param value any type. Non null.
+     * @return true if value can be used directly in comparison instruction, false otherwise.
+     */
+    public boolean isCompareConstant(Value value) {
+        if (!isJavaConstant(value)) {
+            return false;
+        }
+        JavaConstant constant = asJavaConstant(value);
+        if (((AArch64Kind) value.getPlatformKind()).isInteger()) {
+            return AArch64ArithmeticLIRGenerator.isArithmeticConstant(constant);
+        } else {
+            return constant.isDefaultForKind();
+        }
+    }
+
+    /**
+     * Moves trueValue into result if (left & right) == 0, else falseValue.
+     *
+     * @param left Integer kind. Non null.
+     * @param right Integer kind. Non null.
+     * @param trueValue Integer kind. Non null.
+     * @param falseValue Integer kind. Non null.
+     * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
+     */
+    @Override
+    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
+        assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
+        assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
+        ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getLIRKind(), AArch64ArithmeticOp.ANDS, true, left, right);
+        Variable result = newVariable(trueValue.getLIRKind());
+        append(new AArch64ControlFlow.CondMoveOp(result, AArch64Assembler.ConditionFlag.EQ, asAllocatableValue(trueValue), asAllocatableValue(falseValue)));
+        return result;
+    }
+
+    @Override
+    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
+        if (AArch64Call.isNearCall(linkage)) {
+            append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
+        } else {
+            append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
+        }
+    }
+
+    @Override
+    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
+        append(new AArch64ControlFlow.StrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getLIRKind()), AArch64LIRGenerator::toIntConditionFlag));
+    }
+
+    @Override
+    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
+        // Make copy of key since the TableSwitch destroys its input.
+        Variable tmp = emitMove(key);
+        Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
+        append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch));
+    }
+
+    @Override
+    public Variable emitByteSwap(Value operand) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw JVMCIError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
+        // TODO (das) Do not generate until we support vector instructions
+        throw JVMCIError.unimplemented("Do not generate until we support vector instructions");
+    }
+
+    @Override
+    protected JavaConstant zapValueForKind(PlatformKind kind) {
+        long dead = 0xDEADDEADDEADDEADL;
+        switch ((AArch64Kind) kind) {
+            case BYTE:
+                return JavaConstant.forByte((byte) dead);
+            case WORD:
+                return JavaConstant.forShort((short) dead);
+            case DWORD:
+                return JavaConstant.forInt((int) dead);
+            case QWORD:
+                return JavaConstant.forLong(dead);
+            case SINGLE:
+                return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
+            case DOUBLE:
+                return JavaConstant.forDouble(Double.longBitsToDouble(dead));
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * Loads value into virtual register. Contrary to {@link #load(Value)} this handles
+     * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not
+     * creating an unnecessary move into a virtual register.
+     *
+     * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0,
+     * [x0] instead of: ldr x0, [x19].
+     */
+    protected AllocatableValue loadReg(Value val) {
+        if (!(val instanceof Variable || val instanceof RegisterValue)) {
+            return emitMove(val);
+        }
+        return (AllocatableValue) val;
+    }
+
+    /**
+     * If value is a constant that cannot be used directly with a gpCompare instruction load it into
+     * a register and return the register, otherwise return constant value unchanged.
+     */
+    protected Value loadNonCompareConst(Value value) {
+        if (!isCompareConstant(value)) {
+            return loadReg(value);
+        }
+        return value;
+    }
+
+    @Override
+    public void emitPause() {
+        append(new AArch64PauseOp());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64LIRKindTool.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,65 @@
+/*
+ * 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.compiler.aarch64;
+
+import com.oracle.graal.compiler.common.spi.LIRKindTool;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.LIRKind;
+
+public class AArch64LIRKindTool implements LIRKindTool {
+
+    public LIRKind getIntegerKind(int bits) {
+        if (bits <= 8) {
+            return LIRKind.value(AArch64Kind.BYTE);
+        } else if (bits <= 16) {
+            return LIRKind.value(AArch64Kind.WORD);
+        } else if (bits <= 32) {
+            return LIRKind.value(AArch64Kind.DWORD);
+        } else {
+            assert bits <= 64;
+            return LIRKind.value(AArch64Kind.QWORD);
+        }
+    }
+
+    public LIRKind getFloatingKind(int bits) {
+        switch (bits) {
+            case 32:
+                return LIRKind.value(AArch64Kind.SINGLE);
+            case 64:
+                return LIRKind.value(AArch64Kind.DOUBLE);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    public LIRKind getObjectKind() {
+        return LIRKind.reference(AArch64Kind.QWORD);
+    }
+
+    public LIRKind getWordKind() {
+        return LIRKind.value(AArch64Kind.QWORD);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64MoveFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,122 @@
+/*
+ * 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.compiler.aarch64;
+
+import static com.oracle.graal.lir.LIRValueUtil.asConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isConstantValue;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
+
+import com.oracle.graal.compiler.aarch64.AArch64LIRGenerator.ConstantTableBaseProvider;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64Move.LoadAddressOp;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64MoveFactory implements MoveFactory {
+
+    private final CodeCacheProvider codeCache;
+    protected final ConstantTableBaseProvider constantTableBaseProvider;
+
+    public AArch64MoveFactory(CodeCacheProvider codeCache, ConstantTableBaseProvider constantTableBaseProvider) {
+        this.codeCache = codeCache;
+        this.constantTableBaseProvider = constantTableBaseProvider;
+    }
+
+    @Override
+    public LIRInstruction createMove(AllocatableValue dst, Value src) {
+        boolean srcIsSlot = isStackSlotValue(src);
+        boolean dstIsSlot = isStackSlotValue(dst);
+        if (isConstantValue(src)) {
+            return createLoad(dst, asConstant(src));
+        } else if (src instanceof AArch64AddressValue) {
+            return new LoadAddressOp(dst, (AArch64AddressValue) src);
+        } else {
+            assert src instanceof AllocatableValue;
+            if (srcIsSlot && dstIsSlot) {
+                throw JVMCIError.shouldNotReachHere(src.getClass() + " " + dst.getClass());
+            } else {
+                // return new Move(dst, (AllocatableValue) src);
+                throw JVMCIError.unimplemented();
+            }
+        }
+    }
+
+    @Override
+    public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) {
+        // return new AArch64Move.Move(result, input);
+        throw JVMCIError.unimplemented();
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        if (src instanceof JavaConstant) {
+            JavaConstant javaConstant = (JavaConstant) src;
+            if (canInlineConstant(javaConstant)) {
+                // return new AArch64Move.LoadInlineConstant(javaConstant, dst);
+                throw JVMCIError.unimplemented();
+            } else {
+                // return new AArch64Move.LoadConstantFromTable(javaConstant,
+                // constantTableBaseProvider.getConstantTableBase(), dst);
+                throw JVMCIError.unimplemented();
+            }
+        } else {
+            throw JVMCIError.shouldNotReachHere(src.getClass().toString());
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        switch (c.getJavaKind()) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int:
+                // return SPARCAssembler.isSimm13(c.asInt()) && !codeCache.needsDataPatch(c);
+                boolean x = !codeCache.needsDataPatch(c);
+                throw JVMCIError.unimplemented("needsDataPatch=" + x);
+            case Long:
+                // return SPARCAssembler.isSimm13(c.asLong()) && !codeCache.needsDataPatch(c);
+                boolean y = !codeCache.needsDataPatch(c);
+                throw JVMCIError.unimplemented("needsDataPatch=" + y);
+            case Object:
+                return c.isNull();
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64NodeLIRBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,75 @@
+/*
+ * 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.compiler.aarch64;
+
+import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.lir.aarch64.AArch64BreakpointOp;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.BreakpointNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public abstract class AArch64NodeLIRBuilder extends NodeLIRBuilder {
+
+    public AArch64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, AArch64NodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
+    }
+
+    @Override
+    protected boolean peephole(ValueNode valueNode) {
+        // No peephole optimizations for now
+        return false;
+    }
+
+    @Override
+    public void visitBreakpointNode(BreakpointNode node) {
+        JavaType[] sig = new JavaType[node.arguments().size()];
+        for (int i = 0; i < sig.length; i++) {
+            sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
+        }
+
+        Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(CallingConvention.Type.JavaCall, null, sig, gen.target(), false),
+                        node.arguments());
+        append(new AArch64BreakpointOp(parameters));
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) super.getLIRGeneratorTool();
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        // XXX Maybe we need something like this.
+        // getLIRGeneratorTool().emitLoadConstantTableBase();
+        super.emitPrologue(graph);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64NodeMatchRules.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,59 @@
+/*
+ * 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.compiler.aarch64;
+
+import com.oracle.graal.compiler.gen.NodeMatchRules;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.DeoptimizingNode;
+import com.oracle.graal.nodes.memory.Access;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+
+public class AArch64NodeMatchRules extends NodeMatchRules {
+
+    public AArch64NodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AArch64Kind getMemoryKind(Access access) {
+        return (AArch64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
+    }
+
+    @Override
+    public AArch64LIRGenerator getLIRGeneratorTool() {
+        return (AArch64LIRGenerator) gen;
+    }
+
+    protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
+        return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.aarch64/src/com/oracle/graal/compiler/aarch64/AArch64SuitesProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.aarch64;
+
+import com.oracle.graal.java.DefaultSuitesProvider;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.phases.tiers.CompilerConfiguration;
+
+public class AArch64SuitesProvider extends DefaultSuitesProvider {
+
+    public AArch64SuitesProvider(CompilerConfiguration compilerConfiguration, Plugins plugins) {
+        super(compilerConfiguration, plugins);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.compiler.common;
 
-import jdk.vm.ci.options.DerivedOptionValue;
-import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.DerivedOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 
 /**
  * Options to control the backend configuration.
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.compiler.common;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.StableOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
 
 /**
  * This class encapsulates options that control the behavior of the Graal compiler.
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -93,7 +93,7 @@
 
     private TraceBuilder(List<T> blocks) {
         processed = new BitSet(blocks.size());
-        worklist = new PriorityQueue<T>(TraceBuilder::compare);
+        worklist = createQueue();
         assert (worklist != null);
 
         blocked = new int[blocks.size()];
@@ -103,7 +103,12 @@
         }
     }
 
-    private static <T extends AbstractBlockBase<T>> int compare(T a, T b) {
+    @SuppressWarnings("unchecked")
+    private PriorityQueue<T> createQueue() {
+        return (PriorityQueue<T>) new PriorityQueue<AbstractBlockBase<?>>(TraceBuilder::compare);
+    }
+
+    private static int compare(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
         return Double.compare(b.probability(), a.probability());
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java	Tue Jan 05 16:42:05 2016 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.common.util;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
 
@@ -151,6 +152,29 @@
         assert CodeUtil.isPowerOf2(64);
     }
 
+    public interface Stringify {
+        String apply(Object o);
+    }
+
+    public static String join(Collection<?> c, String sep) {
+        return join(c, sep, "", "", null);
+    }
+
+    public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
+        StringBuilder buf = new StringBuilder(prefix);
+        boolean first = true;
+        for (Object e : c) {
+            if (!first) {
+                buf.append(sep);
+            } else {
+                first = false;
+            }
+            buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
+        }
+        buf.append(suffix);
+        return buf.toString();
+    }
+
     /**
      * Sets the element at a given position of a list and ensures that this position exists. If the
      * list is current shorter than the position, intermediate positions are filled with a given
@@ -243,10 +267,10 @@
         boolean newLine = true;
         for (int i = 0; i < length; i++) {
             if (newLine) {
-                TTY.print("%08x: ", address + i);
+                TTY.printf("%08x: ", address + i);
                 newLine = false;
             }
-            TTY.print("%02x ", array[i]);
+            TTY.printf("%02x ", array[i]);
             if (i % bytesPerLine == bytesPerLine - 1) {
                 TTY.println();
                 newLine = true;
--- a/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Tue Jan 05 16:42:05 2016 -0800
@@ -63,7 +63,6 @@
 import javax.tools.StandardLocation;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.compiler.match.ComplexMatchResult;
@@ -75,6 +74,7 @@
 import com.oracle.graal.compiler.match.MatchableNodes;
 import com.oracle.graal.graph.Position;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCArithmeticLIRGenerator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCArithmeticLIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -457,7 +457,7 @@
                 op = Op3s.Sllx;
                 break;
             default:
-                throw JVMCIError.shouldNotReachHere();
+                throw JVMCIError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
         }
         return emitBinary(resultKind, op, a, b);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConstantArrayReadFoldingTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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.compiler.test;
+
+import org.junit.Test;
+
+public class ConstantArrayReadFoldingTest extends GraalCompilerTest {
+
+    enum E {
+        A(0.001),
+        B(0.01),
+        C(0.5),
+        D(2.0),
+        E(3.0),
+        F(4.0),
+        G(5.0);
+
+        public final double ceiling;
+        public double weight;
+
+        private E(double ceiling) {
+            this.ceiling = ceiling;
+        }
+    }
+
+    public Object test1Snippet(double value) {
+        for (E kind : E.values()) {
+            if (value <= kind.ceiling) {
+                return kind;
+            }
+        }
+        throw new IllegalArgumentException();
+    }
+
+    @Test
+    public void test1() {
+        test("test1Snippet", 1.0);
+        test("test1Snippet", 2.0);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CountedLoopTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -227,7 +227,7 @@
         public void rewrite(LoopsData loops) {
             InductionVariable inductionVariable = loops.getInductionVariable(iv);
             ValueNode node = property.get(inductionVariable);
-            graph().replaceFloating(this, node);
+            replaceAtUsagesAndDelete(node);
         }
 
         public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -58,7 +58,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog;
-import jdk.vm.ci.options.DerivedOptionValue;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -92,6 +91,7 @@
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
@@ -102,6 +102,7 @@
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.options.DerivedOptionValue;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.Phase;
@@ -348,6 +349,7 @@
     protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) {
         SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
         schedule.apply(graph);
+        ScheduleResult scheduleResult = graph.getLastSchedule();
 
         NodeMap<Integer> canonicalId = graph.createNodeMap();
         int nextId = 0;
@@ -355,9 +357,9 @@
         List<String> constantsLines = new ArrayList<>();
 
         StringBuilder result = new StringBuilder();
-        for (Block block : schedule.getCFG().getBlocks()) {
+        for (Block block : scheduleResult.getCFG().getBlocks()) {
             result.append("Block " + block + " ");
-            if (block == schedule.getCFG().getStartBlock()) {
+            if (block == scheduleResult.getCFG().getStartBlock()) {
                 result.append("* ");
             }
             result.append("-> ");
@@ -365,7 +367,7 @@
                 result.append(succ + " ");
             }
             result.append("\n");
-            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+            for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
                 if (node instanceof ValueNode && node.isAlive()) {
                     if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof InfopointNode)) {
                         if (node instanceof ConstantNode) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraphScheduleTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,6 +29,7 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeMap;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.phases.schedule.SchedulePhase;
 
@@ -37,10 +38,10 @@
     protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) {
         SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST);
         ibp.apply(graph);
-        assertOrderedAfterSchedule(ibp, a, b);
+        assertOrderedAfterSchedule(graph.getLastSchedule(), a, b);
     }
 
-    protected void assertOrderedAfterSchedule(SchedulePhase ibp, Node a, Node b) {
+    protected void assertOrderedAfterSchedule(ScheduleResult ibp, Node a, Node b) {
         NodeMap<Block> nodeToBlock = ibp.getCFG().getNodeToBlock();
         Block bBlock = nodeToBlock.get(b);
         Block aBlock = nodeToBlock.get(a);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
-
 import org.junit.Test;
 
 import com.oracle.graal.debug.Debug;
@@ -216,8 +214,10 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         ParameterNode param = graph.getNodes(ParameterNode.TYPE).iterator().next();
         ConstantNode constant = ConstantNode.forInt(0, graph);
-        for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
-            n.replaceFirstInput(param, constant);
+        for (Node n : param.usages().snapshot()) {
+            if (!(n instanceof FrameState)) {
+                n.replaceFirstInput(param, constant);
+            }
         }
         Debug.dump(graph, "Graph");
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,10 +27,8 @@
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.DebugDumpScope;
-import com.oracle.graal.graph.Node;
 import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
-import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
@@ -132,12 +130,8 @@
         new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph);
 
         // Framestates create comparison problems
-        for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) {
-            ((StateSplit) stateSplit).setStateAfter(null);
-        }
-        for (Node stateSplit : referenceGraph.getNodes().filterInterface(StateSplit.class)) {
-            ((StateSplit) stateSplit).setStateAfter(null);
-        }
+        graph.clearAllStateAfter();
+        referenceGraph.clearAllStateAfter();
 
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,9 +31,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -42,17 +39,17 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.StartNode;
-import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.memory.FloatingReadNode;
 import com.oracle.graal.nodes.memory.WriteNode;
 import com.oracle.graal.nodes.spi.LoweringTool;
-import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.FloatingReadPhase;
@@ -107,7 +104,7 @@
     @Test
     public void testSimple() {
         for (TestMode mode : TestMode.values()) {
-            SchedulePhase schedule = getFinalSchedule("testSimpleSnippet", mode);
+            ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode);
             StructuredGraph graph = schedule.getCFG().graph;
             assertReadAndWriteInSameBlock(schedule, true);
             assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first());
@@ -132,7 +129,7 @@
     @Test
     public void testSplit1() {
         for (TestMode mode : TestMode.values()) {
-            SchedulePhase schedule = getFinalSchedule("testSplit1Snippet", mode);
+            ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode);
             assertReadWithinStartBlock(schedule, true);
             assertReadWithinAllReturnBlocks(schedule, false);
         }
@@ -156,7 +153,7 @@
 
     @Test
     public void testSplit2() {
-        SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -180,7 +177,7 @@
 
     @Test
     public void testLoop1() {
-        SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -205,7 +202,7 @@
 
     @Test
     public void testLoop2() {
-        SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -227,7 +224,7 @@
 
     @Test
     public void testLoop3() {
-        SchedulePhase schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(6, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -263,7 +260,7 @@
 
     @Test
     public void testLoop5() {
-        SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -292,7 +289,7 @@
 
     @Test
     public void testLoop6() {
-        SchedulePhase schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(13, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -325,7 +322,7 @@
 
     @Test
     public void testLoop7() {
-        SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(18, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -352,7 +349,7 @@
 
     @Test
     public void testLoop8() {
-        SchedulePhase schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(10, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -372,7 +369,7 @@
 
     @Test
     public void testLoop9() {
-        SchedulePhase schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1));
         ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
@@ -391,7 +388,7 @@
 
     @Test
     public void testArrayCopy() {
-        SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
         ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
@@ -413,7 +410,7 @@
 
     @Test
     public void testIfRead1() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -434,7 +431,7 @@
 
     @Test
     public void testIfRead2() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
         assertReadWithinStartBlock(schedule, false);
@@ -456,7 +453,7 @@
 
     @Test
     public void testIfRead3() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -477,7 +474,7 @@
 
     @Test
     public void testIfRead4() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(3, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -496,7 +493,7 @@
 
     @Test
     public void testIfRead5() {
-        SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -522,7 +519,7 @@
 
     @Test
     public void testAntiDependency() {
-        SchedulePhase schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
         assertDeepEquals(4, schedule.getCFG().getBlocks().size());
         assertReadBeforeAllWritesInStartBlock(schedule);
     }
@@ -546,7 +543,7 @@
 
     @Test
     public void testBlockSchedule() {
-        SchedulePhase schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().graph;
         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 
@@ -587,7 +584,7 @@
 
     @Test
     public void testBlockSchedule2() {
-        SchedulePhase schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
+        ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -610,7 +607,7 @@
 
     @Test
     public void testProxy() {
-        SchedulePhase schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -633,7 +630,7 @@
 
     @Test
     public void testStringHashCode() {
-        SchedulePhase schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
 
@@ -665,12 +662,12 @@
 
     @Test
     public void testLoop4() {
-        SchedulePhase schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
+        ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
 
-    private void assertReadWithinAllReturnBlocks(SchedulePhase schedule, boolean withinReturnBlock) {
+    private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) {
         StructuredGraph graph = schedule.getCFG().graph;
         assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty());
 
@@ -689,7 +686,7 @@
         assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
     }
 
-    private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) {
+    private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) {
         boolean readEncountered = false;
         for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
             if (node instanceof FloatingReadNode) {
@@ -699,14 +696,14 @@
         assertDeepEquals(withinStartBlock, readEncountered);
     }
 
-    private static void assertReadAndWriteInSameBlock(SchedulePhase schedule, boolean inSame) {
+    private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) {
         StructuredGraph graph = schedule.getCFG().graph;
         FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
         WriteNode write = graph.getNodes().filter(WriteNode.class).first();
         assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
     }
 
-    private static void assertReadBeforeAllWritesInStartBlock(SchedulePhase schedule) {
+    private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) {
         boolean writeNodeFound = false;
         boolean readNodeFound = false;
         for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
@@ -720,12 +717,12 @@
         assertTrue(readNodeFound);
     }
 
-    private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) {
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) {
         return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS);
     }
 
     @SuppressWarnings("try")
-    private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
+    private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
         final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
             try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
@@ -737,15 +734,7 @@
                 }
                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
                 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
-                    for (Node node : graph.getNodes()) {
-                        if (node instanceof StateSplit) {
-                            FrameState stateAfter = ((StateSplit) node).stateAfter();
-                            if (stateAfter != null) {
-                                ((StateSplit) node).setStateAfter(null);
-                                GraphUtil.killWithUnusedFloatingInputs(stateAfter);
-                            }
-                        }
-                    }
+                    graph.clearAllStateAfter();
                 }
                 Debug.dump(graph, "after removal of framestates");
 
@@ -760,7 +749,7 @@
                 SchedulePhase schedule = new SchedulePhase(schedulingStrategy);
                 schedule.apply(graph);
                 assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
-                return schedule;
+                return graph.getLastSchedule();
             }
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
-
 import java.util.HashMap;
 import java.util.Map;
 
@@ -94,8 +92,10 @@
         ParameterNode param = graph.getNodes(ParameterNode.TYPE).first();
         if (param != null) {
             ConstantNode constant = ConstantNode.forInt(0, graph);
-            for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
-                n.replaceFirstInput(param, constant);
+            for (Node n : param.usages().snapshot()) {
+                if (!(n instanceof FrameState)) {
+                    n.replaceFirstInput(param, constant);
+                }
             }
         }
         Map<Invoke, Double> hints = new HashMap<>();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OptionsVerifierTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/OptionsVerifierTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -48,12 +48,13 @@
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
-import jdk.vm.ci.options.OptionDescriptor;
-import jdk.vm.ci.options.OptionDescriptors;
-import jdk.vm.ci.options.OptionValue;
 
 import org.junit.Test;
 
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionDescriptors;
+import com.oracle.graal.options.OptionValue;
+
 /**
  * Verifies a class declaring one or more {@linkplain OptionValue options} has a class initializer
  * that only initializes the option(s). This sanity check mitigates the possibility of an option
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.LoopExitNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.calc.AddNode;
 import com.oracle.graal.nodes.calc.BinaryArithmeticNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -59,8 +60,9 @@
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST);
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
         assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
         LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java	Tue Jan 05 16:42:05 2016 -0800
@@ -37,6 +37,7 @@
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.calc.AddNode;
 import com.oracle.graal.nodes.calc.BinaryArithmeticNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -69,8 +70,9 @@
         returnNode.replaceAtPredecessor(beginNode);
         beginNode.setNext(returnNode);
         Debug.dump(graph, "Graph");
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
         NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
         assertDeepEquals(2, schedule.getCFG().getBlocks().size());
@@ -103,8 +105,8 @@
         FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase();
         phase.apply(graph);
 
-        schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-        schedule.apply(graph);
+        schedulePhase.apply(graph);
+        schedule = graph.getLastSchedule();
         blockToNodesMap = schedule.getBlockToNodesMap();
         nodeToBlock = schedule.getNodeToBlockMap();
         for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -39,6 +39,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.java.CheckCastNode;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
@@ -191,6 +192,8 @@
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+        new ConditionalEliminationPhase().apply(referenceGraph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
     }
@@ -206,8 +209,9 @@
 
     public static void outputGraph(StructuredGraph graph, String message) {
         TTY.println("========================= " + message);
-        SchedulePhase schedule = new SchedulePhase();
-        schedule.apply(graph);
+        SchedulePhase schedulePhase = new SchedulePhase();
+        schedulePhase.apply(graph);
+        ScheduleResult schedule = graph.getLastSchedule();
         for (Block block : schedule.getCFG().getBlocks()) {
             TTY.print("Block " + block + " ");
             if (block == schedule.getCFG().getStartBlock()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -34,7 +34,6 @@
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.phases.OptimisticOptimizations;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public abstract class BackendTest extends GraalCompilerTest {
 
@@ -48,15 +47,14 @@
 
     @SuppressWarnings("try")
     protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
-        SchedulePhase schedule = null;
         try (Scope s = Debug.scope("FrontEnd")) {
-            schedule = GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.method().getProfilingInfo(), getSuites());
+            GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.method().getProfilingInfo(), getSuites());
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), schedule, graph, null, cc, null, getLIRSuites());
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), graph, null, cc, null, getLIRSuites());
         return lirGen;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -130,6 +130,20 @@
     }
 
     @Test
+    public void testArrayCopy() {
+        testPartialEscapeAnalysis("testArrayCopySnippet", 0, 0);
+    }
+
+    public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"};
+
+    public static Object testArrayCopySnippet(int a) {
+        Object[] tmp = new Object[]{a != 1 ? array[a] : null};
+        Object[] tmp2 = new Object[5];
+        System.arraycopy(tmp, 0, tmp2, 4, 1);
+        return tmp2[4];
+    }
+
+    @Test
     @Ignore
     public void testCache() {
         testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -44,8 +44,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.TriState;
 import jdk.vm.ci.meta.VMConstant;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import com.oracle.graal.compiler.LIRGenerationPhase.LIRGenerationContext;
 import com.oracle.graal.compiler.common.alloc.ComputeBlockOrder;
@@ -70,8 +68,11 @@
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
 import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
@@ -176,8 +177,8 @@
     public static <T extends CompilationResult> T compile(Request<T> r) {
         assert !r.graph.isFrozen();
         try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
-            SchedulePhase schedule = emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
-            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, schedule, null, r.lirSuites);
+            emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
+            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -196,7 +197,7 @@
      * Builds the graph, optimizes it.
      */
     @SuppressWarnings("try")
-    public static SchedulePhase emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
+    public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
                     ProfilingInfo profilingInfo, Suites suites) {
         try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) {
             HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
@@ -219,12 +220,8 @@
 
             LowTierContext lowTierContext = new LowTierContext(providers, target);
             suites.getLowTier().apply(graph, lowTierContext);
-            graph.maybeCompress();
 
-            SchedulePhase schedule = new SchedulePhase();
-            schedule.apply(graph);
-            Debug.dump(schedule, "Final HIR schedule");
-            return schedule;
+            Debug.dump(graph.getLastSchedule(), "Final HIR schedule");
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -232,17 +229,17 @@
 
     @SuppressWarnings("try")
     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult,
-                    CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) {
-        try (Scope s = Debug.scope("BackEnd", schedule); DebugCloseable a = BackEnd.start()) {
+                    CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) {
+        try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) {
             // Repeatedly run the LIR code generation pass to improve statistical profiling results.
             for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
                 SchedulePhase dummySchedule = new SchedulePhase();
                 dummySchedule.apply(graph);
-                emitLIR(backend, dummySchedule, graph, stub, cc, registerConfig, lirSuites);
+                emitLIR(backend, graph, stub, cc, registerConfig, lirSuites);
             }
 
             LIRGenerationResult lirGen = null;
-            lirGen = emitLIR(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+            lirGen = emitLIR(backend, graph, stub, cc, registerConfig, lirSuites);
             try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
                 int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
                 compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
@@ -256,14 +253,14 @@
     }
 
     @SuppressWarnings("try")
-    public static LIRGenerationResult emitLIR(Backend backend, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
+    public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
         try {
-            return emitLIR0(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+            return emitLIR0(backend, graph, stub, cc, registerConfig, lirSuites);
         } catch (OutOfRegistersException e) {
             if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
                 try (OverrideScope s = OptionValue.override(RegisterPressure, ALL_REGISTERS)) {
                     // retry with default register set
-                    return emitLIR0(backend, schedule, graph, stub, cc, registerConfig, lirSuites);
+                    return emitLIR0(backend, graph, stub, cc, registerConfig, lirSuites);
                 }
             } else {
                 throw e;
@@ -272,8 +269,9 @@
     }
 
     @SuppressWarnings("try")
-    private static LIRGenerationResult emitLIR0(Backend backend, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
+    private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig, LIRSuites lirSuites) {
         try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) {
+            ScheduleResult schedule = graph.getLastSchedule();
             List<Block> blocks = schedule.getCFG().getBlocks();
             Block startBlock = schedule.getCFG().getStartBlock();
             assert startBlock != null;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompilerOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompilerOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.compiler;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Options related to {@link GraalCompiler}.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugInitializationPropertyProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugInitializationPropertyProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.compiler;
 
-import jdk.vm.ci.service.ServiceProvider;
-
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugInitializationPropertyProvider;
 import com.oracle.graal.debug.GraalDebugConfig;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * Sets system properties used in the initialization of {@link Debug} based on the values specified
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,9 +36,9 @@
 import com.oracle.graal.lir.phases.LIRPhase;
 import com.oracle.graal.lir.ssa.SSAUtil;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public class LIRGenerationPhase extends LIRPhase<LIRGenerationPhase.LIRGenerationContext> {
 
@@ -46,9 +46,9 @@
         private final NodeLIRBuilderTool nodeLirBuilder;
         private final LIRGeneratorTool lirGen;
         private final StructuredGraph graph;
-        private final SchedulePhase schedule;
+        private final ScheduleResult schedule;
 
-        public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, SchedulePhase schedule) {
+        public LIRGenerationContext(LIRGeneratorTool lirGen, NodeLIRBuilderTool nodeLirBuilder, StructuredGraph graph, ScheduleResult schedule) {
             this.nodeLirBuilder = nodeLirBuilder;
             this.lirGen = lirGen;
             this.graph = graph;
@@ -61,7 +61,7 @@
                     LIRGenerationPhase.LIRGenerationContext context) {
         NodeLIRBuilderTool nodeLirBuilder = context.nodeLirBuilder;
         StructuredGraph graph = context.graph;
-        SchedulePhase schedule = context.schedule;
+        ScheduleResult schedule = context.schedule;
         for (B b : linearScanOrder) {
             emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap());
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,7 +31,7 @@
 import java.util.Map.Entry;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.debug.Debug;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,6 +29,7 @@
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ExpandLogicPhase;
 import com.oracle.graal.phases.common.LoweringPhase;
+import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class EconomyLowTier extends PhaseSuite<LowTierContext> {
@@ -42,5 +43,7 @@
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
 
         appendPhase(new ExpandLogicPhase());
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -33,9 +33,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.PartialEscapeAnalysis;
 import static com.oracle.graal.compiler.common.GraalOptions.UseGraalInstrumentation;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.LoopPolicies;
@@ -43,6 +40,9 @@
 import com.oracle.graal.loop.phases.LoopPeelingPhase;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
 import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,11 +27,11 @@
 import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
 import static com.oracle.graal.compiler.common.GraalOptions.UseGraalInstrumentation;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
@@ -42,6 +42,7 @@
 import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.common.UseTrappingNullChecksPhase;
 import com.oracle.graal.phases.common.instrumentation.InlineInstrumentationPhase;
+import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class LowTier extends PhaseSuite<LowTierContext> {
@@ -84,5 +85,7 @@
         appendPhase(new UseTrappingNullChecksPhase());
 
         appendPhase(new DeadCodeEliminationPhase(Required));
+
+        appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.FINAL_SCHEDULE));
     }
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Tue Jan 05 16:42:05 2016 -0800
@@ -40,7 +40,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.debug.DelegatingDebugConfig.Level;
 import com.oracle.graal.debug.internal.DebugHistogramImpl;
@@ -1404,7 +1404,7 @@
     }
 
     private static boolean findMatch(Set<String> haystack, Set<String> haystackSubstrings, String needle) {
-        if (haystack.isEmpty()) {
+        if (haystack.isEmpty() && haystackSubstrings.isEmpty()) {
             // Empty haystack means match all
             return true;
         }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugEnvironment.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugEnvironment.java	Tue Jan 05 16:42:05 2016 -0800
@@ -35,7 +35,7 @@
 import java.util.List;
 
 import jdk.vm.ci.runtime.JVMCI;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 public class DebugEnvironment {
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,11 +29,12 @@
 import java.util.List;
 import java.util.Set;
 
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.JavaMethod;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 public class GraalDebugConfig implements DebugConfig {
     @SuppressWarnings("all")
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Tue Jan 05 16:42:05 2016 -0800
@@ -30,7 +30,7 @@
 import java.util.Map;
 import java.util.regex.Pattern;
 
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 /**
  * A collection of static methods for printing debug and informational output to a global
@@ -235,7 +235,7 @@
         out().println(f);
     }
 
-    public static void print(String format, Object... args) {
+    public static void printf(String format, Object... args) {
         out().printf(format, args);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,9 +32,6 @@
 import java.util.function.Consumer;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.CollectionsFactory;
 import com.oracle.graal.debug.Debug;
@@ -44,6 +41,9 @@
 import com.oracle.graal.debug.Fingerprint;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.NodeIterable;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * This class is a graph container, it contains the set of nodes that belong to this graph.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Jan 05 16:42:05 2016 -0800
@@ -188,6 +188,12 @@
          * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
+
+        /**
+         * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null.
+         * Generally used in conjunction with {@link #setStampFromReturnType()}.
+         */
+        boolean returnStampIsNonNull() default false;
     }
 
     /**
@@ -670,10 +676,24 @@
     }
 
     public final void replaceAtUsages(Node other) {
-        replaceAtUsages(other, null);
+        replaceAtUsages(other, null, null);
     }
 
     public final void replaceAtUsages(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, null);
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other) {
+        replaceAtUsages(other, null, this);
+        safeDelete();
+    }
+
+    public final void replaceAtUsagesAndDelete(Node other, Predicate<Node> filter) {
+        replaceAtUsages(other, filter, this);
+        safeDelete();
+    }
+
+    protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
         assert checkReplaceWith(other);
         int i = 0;
         while (i < this.getUsageCount()) {
@@ -681,7 +701,12 @@
             if (filter == null || filter.test(usage)) {
                 boolean result = usage.getNodeClass().getInputEdges().replaceFirst(usage, this, other);
                 assert assertTrue(result, "not found in inputs, usage: %s", usage);
-                maybeNotifyInputChanged(usage);
+                /*
+                 * Don't notify for nodes which are about to be deleted.
+                 */
+                if (toBeDeleted == null || usage != toBeDeleted) {
+                    maybeNotifyInputChanged(usage);
+                }
                 if (other != null) {
                     other.addUsage(usage);
                 }
@@ -823,6 +848,7 @@
     }
 
     private boolean checkDeletion() {
+        assertTrue(isAlive(), "must be alive");
         assertTrue(hasNoUsages(), "cannot delete node %s because of usages: %s", this, usages());
         assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
         return true;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Tue Jan 05 16:42:05 2016 -0800
@@ -220,11 +220,6 @@
     }
 
     @Override
-    public NodeIterable<Node> distinct() {
-        return this;
-    }
-
-    @Override
     public int count() {
         int count = 0;
         for (long l : bits) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctFilteredNodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2012, 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.graph.iterators;
-
-import java.util.Iterator;
-
-import com.oracle.graal.graph.Node;
-
-public class DistinctFilteredNodeIterable<T extends Node> extends FilteredNodeIterable<T> {
-
-    public DistinctFilteredNodeIterable(NodeIterable<T> nodeIterable) {
-        super(nodeIterable);
-    }
-
-    @Override
-    public DistinctFilteredNodeIterable<T> distinct() {
-        return this;
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return new DistinctPredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate);
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Tue Jan 05 16:32:42 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2012, 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.graph.iterators;
-
-import java.util.Iterator;
-
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.NodeBitMap;
-
-public class DistinctPredicatedProxyNodeIterator<T extends Node> extends PredicatedProxyNodeIterator<T> {
-
-    private NodeBitMap visited;
-
-    public DistinctPredicatedProxyNodeIterator(Iterator<T> iterator, NodePredicate predicate) {
-        super(iterator, predicate);
-    }
-
-    @Override
-    protected void forward() {
-        if (current == null) {
-            super.forward();
-            while (!accept(current)) {
-                current = null;
-                super.forward();
-            }
-        }
-    }
-
-    private boolean accept(T n) {
-        if (n == null) {
-            return true;
-        }
-        if (visited == null) {
-            visited = n.graph().createNodeBitMap();
-        }
-        boolean accept = !visited.isMarked(n);
-        visited.mark(n);
-        return accept;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -40,24 +40,6 @@
         return this;
     }
 
-    public FilteredNodeIterable<T> or(NodePredicate nodePredicate) {
-        this.predicate = this.predicate.or(nodePredicate);
-        return this;
-    }
-
-    @Override
-    public FilteredNodeIterable<T> nonNull() {
-        this.predicate = this.predicate.and(NodePredicates.isNotNull());
-        return this;
-    }
-
-    @Override
-    public DistinctFilteredNodeIterable<T> distinct() {
-        DistinctFilteredNodeIterable<T> distinct = new DistinctFilteredNodeIterable<>(nodeIterable);
-        distinct.predicate = predicate;
-        return distinct;
-    }
-
     @Override
     public Iterator<T> iterator() {
         return new PredicatedProxyNodeIterator<>(nodeIterable.iterator(), predicate);
@@ -74,8 +56,4 @@
         return this.and(p);
     }
 
-    @Override
-    public FilteredNodeIterable<T> filterInterface(Class<?> iface) {
-        return this.and(NodePredicates.isAInterface(iface));
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,22 +36,10 @@
         return (NodeIterable<F>) new FilteredNodeIterable<>(this).and(NodePredicates.isA(clazz));
     }
 
-    default NodeIterable<T> filterInterface(Class<?> iface) {
-        return new FilteredNodeIterable<>(this).and(NodePredicates.isAInterface(iface));
-    }
-
     default FilteredNodeIterable<T> filter(NodePredicate predicate) {
         return new FilteredNodeIterable<>(this).and(predicate);
     }
 
-    default FilteredNodeIterable<T> nonNull() {
-        return new FilteredNodeIterable<>(this).and(NodePredicates.isNotNull());
-    }
-
-    default NodeIterable<T> distinct() {
-        return new FilteredNodeIterable<>(this).distinct();
-    }
-
     default List<T> snapshot() {
         ArrayList<T> list = new ArrayList<>();
         snapshotTo(list);
@@ -91,6 +79,13 @@
     }
 
     default boolean contains(T node) {
-        return this.filter(NodePredicates.equals(node)).isNotEmpty();
+        Iterator<T> iterator = iterator();
+        while (iterator.hasNext()) {
+            T next = iterator.next();
+            if (next == node) {
+                return true;
+            }
+        }
+        return false;
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicate.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicate.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,8 +24,6 @@
 
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodePredicates.AndPredicate;
-import com.oracle.graal.graph.iterators.NodePredicates.NotPredicate;
-import com.oracle.graal.graph.iterators.NodePredicates.OrPredicate;
 
 public interface NodePredicate {
 
@@ -34,12 +32,4 @@
     default NodePredicate and(NodePredicate np) {
         return new AndPredicate(this, np);
     }
-
-    default NodePredicate or(NodePredicate np) {
-        return new OrPredicate(this, np);
-    }
-
-    default NodePredicate negate() {
-        return new NotPredicate(this);
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicates.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodePredicates.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,7 +29,6 @@
     private static final TautologyPredicate TAUTOLOGY = new TautologyPredicate();
     private static final ContradictionPredicate CONTRADICTION = new ContradictionPredicate();
     private static final IsNullPredicate IS_NULL = new IsNullPredicate();
-    private static final IsNotNullPredicate IS_NOT_NULL = new IsNotNullPredicate();
 
     public static NodePredicate alwaysTrue() {
         return TAUTOLOGY;
@@ -43,18 +42,6 @@
         return IS_NULL;
     }
 
-    public static NodePredicate isNotNull() {
-        return IS_NOT_NULL;
-    }
-
-    public static NodePredicate equals(Node n) {
-        return new EqualsPredicate(n);
-    }
-
-    public static NodePredicate not(NodePredicate a) {
-        return a.negate();
-    }
-
     public static NegativeTypePredicate isNotA(Class<? extends Node> clazz) {
         return new NegativeTypePredicate(clazz);
     }
@@ -63,16 +50,6 @@
         return new PositiveTypePredicate(clazz);
     }
 
-    public static NodePredicate isAInterface(Class<?> iface) {
-        assert iface.isInterface();
-        return new PositiveTypePredicate(iface);
-    }
-
-    public static NodePredicate isNotAInterface(Class<?> iface) {
-        assert iface.isInterface();
-        return new NegativeTypePredicate(iface);
-    }
-
     static final class TautologyPredicate implements NodePredicate {
 
         @Override
@@ -83,14 +60,6 @@
         public NodePredicate and(NodePredicate np) {
             return np;
         }
-
-        public NodePredicate negate() {
-            return CONTRADICTION;
-        }
-
-        public NodePredicate or(NodePredicate np) {
-            return this;
-        }
     }
 
     static final class ContradictionPredicate implements NodePredicate {
@@ -103,14 +72,6 @@
         public NodePredicate and(NodePredicate np) {
             return this;
         }
-
-        public NodePredicate negate() {
-            return TAUTOLOGY;
-        }
-
-        public NodePredicate or(NodePredicate np) {
-            return np;
-        }
     }
 
     static final class AndPredicate implements NodePredicate {
@@ -147,80 +108,12 @@
         }
     }
 
-    static final class OrPredicate implements NodePredicate {
-
-        private final NodePredicate a;
-        private final NodePredicate b;
-
-        OrPredicate(NodePredicate a, NodePredicate b) {
-            this.a = a;
-            this.b = b;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return a.apply(n) || b.apply(n);
-        }
-    }
-
     static final class IsNullPredicate implements NodePredicate {
 
         @Override
         public boolean apply(Node n) {
             return n == null;
         }
-
-        public NodePredicate negate() {
-            return IS_NOT_NULL;
-        }
-    }
-
-    static final class IsNotNullPredicate implements NodePredicate {
-
-        @Override
-        public boolean apply(Node n) {
-            return n != null;
-        }
-
-        public NodePredicate negate() {
-            return IS_NULL;
-        }
-    }
-
-    static final class EqualsPredicate implements NodePredicate {
-
-        private final Node u;
-
-        EqualsPredicate(Node u) {
-            this.u = u;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return u == n;
-        }
-
-        public NodePredicate negate() {
-            return new NotEqualsPredicate(u);
-        }
-    }
-
-    static final class NotEqualsPredicate implements NodePredicate {
-
-        private final Node u;
-
-        NotEqualsPredicate(Node u) {
-            this.u = u;
-        }
-
-        @Override
-        public boolean apply(Node n) {
-            return u != n;
-        }
-
-        public NodePredicate negate() {
-            return new EqualsPredicate(u);
-        }
     }
 
     public static final class PositiveTypePredicate implements NodePredicate {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotBackend.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,352 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.compiler.common.GraalOptions.ZapStackOnMethodEntry;
+import static java.lang.reflect.Modifier.isStatic;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.aarch64.AArch64.r10;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.CallingConvention.Type.JavaCallee;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import java.lang.reflect.Field;
+import java.util.Set;
+
+import com.oracle.graal.asm.Assembler;
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import com.oracle.graal.compiler.aarch64.AArch64NodeMatchRules;
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.HotSpotHostBackend;
+import com.oracle.graal.hotspot.meta.HotSpotForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.stubs.Stub;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.aarch64.AArch64FrameMap;
+import com.oracle.graal.lir.aarch64.AArch64FrameMapBuilder;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
+import com.oracle.graal.lir.asm.FrameContext;
+import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.lir.framemap.FrameMapBuilder;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CompilationResult;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * HotSpot AArch64 specific backend.
+ */
+public class AArch64HotSpotBackend extends HotSpotHostBackend {
+
+    public AArch64HotSpotBackend(HotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        super(config, runtime, providers);
+    }
+
+    @Override
+    public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+    }
+
+    @Override
+    public FrameMap newFrameMap(RegisterConfig registerConfig) {
+        return new AArch64FrameMap(getCodeCache(), registerConfig, this);
+    }
+
+    @Override
+    public LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes) {
+        return new AArch64HotSpotLIRGenerator(getProviders(), config(), cc, lirGenRes);
+    }
+
+    @Override
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new AArch64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
+    }
+
+    @Override
+    public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+        return new AArch64HotSpotNodeLIRBuilder(graph, lirGen, new AArch64NodeMatchRules(lirGen));
+    }
+
+    /**
+     * Emits code to do stack overflow checking.
+     *
+     * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate
+     *            the current frame
+     */
+    protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int pagesToBang, boolean afterFrameInit) {
+        if (pagesToBang > 0) {
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            int frameSize = crb.frameMap.totalFrameSize();
+            if (frameSize > 0) {
+                int lastFramePage = frameSize / UNSAFE.pageSize();
+                // emit multiple stack bangs for methods with frames larger than a page
+                for (int i = 0; i <= lastFramePage; i++) {
+                    int disp = (i + pagesToBang) * UNSAFE.pageSize();
+                    if (afterFrameInit) {
+                        disp -= frameSize;
+                    }
+                    crb.blockComment("[stack overflow check]");
+                    try (ScratchRegister sc = masm.getScratchRegister()) {
+                        Register scratch = sc.getRegister();
+                        AArch64Address address = masm.makeAddress(sp, -disp, scratch, 8, /* allowOverwrite */false);
+                        masm.str(64, zr, address);
+                    }
+                }
+            }
+        }
+    }
+
+    private class HotSpotFrameContext implements FrameContext {
+        final boolean isStub;
+
+        HotSpotFrameContext(boolean isStub) {
+            this.isStub = isStub;
+        }
+
+        @Override
+        public void enter(CompilationResultBuilder crb) {
+            FrameMap frameMap = crb.frameMap;
+            final int frameSize = frameMap.frameSize();
+            final int totalFrameSize = frameMap.totalFrameSize();
+            assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words";
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            if (!isStub && pagesToBang > 0) {
+                emitStackOverflowCheck(crb, pagesToBang, false);
+            }
+            crb.blockComment("[method prologue]");
+
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                // save link register and framepointer
+                masm.mov(64, scratch, sp);
+                AArch64Address address = AArch64Address.createPreIndexedImmediateAddress(scratch, -crb.target.arch.getWordSize());
+                masm.str(64, lr, address);
+                masm.str(64, fp, address);
+                // Update framepointer
+                masm.mov(64, fp, scratch);
+
+                if (ZapStackOnMethodEntry.getValue()) {
+                    int intSize = 4;
+                    address = AArch64Address.createPreIndexedImmediateAddress(scratch, -intSize);
+                    try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                        Register value = sc2.getRegister();
+                        masm.mov(value, 0xC1C1C1C1);
+                        for (int i = 0; i < frameSize; i += intSize) {
+                            masm.str(32, value, address);
+                        }
+                    }
+                    masm.mov(64, sp, scratch);
+                } else {
+                    if (AArch64MacroAssembler.isArithmeticImmediate(totalFrameSize)) {
+                        masm.sub(64, sp, scratch, frameSize);
+                    } else {
+                        try (ScratchRegister sc2 = masm.getScratchRegister()) {
+                            Register scratch2 = sc2.getRegister();
+                            masm.mov(scratch2, frameSize);
+                            masm.sub(64, sp, scratch, scratch2);
+                        }
+                    }
+                }
+            }
+            crb.blockComment("[code body]");
+        }
+
+        @Override
+        public void leave(CompilationResultBuilder crb) {
+            AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+            crb.blockComment("[method epilogue]");
+            final int frameSize = crb.frameMap.totalFrameSize();
+            if (AArch64MacroAssembler.isArithmeticImmediate(frameSize)) {
+                masm.add(64, sp, sp, frameSize);
+            } else {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
+                    Register scratch = sc.getRegister();
+                    masm.mov(scratch, frameSize);
+                    masm.add(64, sp, sp, scratch);
+                }
+            }
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                // restore link register and framepointer
+                masm.mov(64, scratch, sp);
+                AArch64Address address = AArch64Address.createPostIndexedImmediateAddress(scratch, crb.target.arch.getWordSize());
+                masm.ldr(64, fp, address);
+                masm.ldr(64, lr, address);
+                masm.mov(64, sp, scratch);
+            }
+        }
+
+        @Override
+        public boolean hasFrame() {
+            return true;
+        }
+    }
+
+    @Override
+    protected Assembler createAssembler(FrameMap frameMap) {
+        return new AArch64MacroAssembler(getTarget());
+    }
+
+    @Override
+    public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+        AArch64HotSpotLIRGenerationResult gen = (AArch64HotSpotLIRGenerationResult) lirGenRen;
+        LIR lir = gen.getLIR();
+        assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+
+        Stub stub = gen.getStub();
+        Assembler masm = createAssembler(frameMap);
+        HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
+
+        CompilationResultBuilder crb = new CompilationResultBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, frameContext, compilationResult);
+        crb.setTotalFrameSize(frameMap.frameSize());
+        StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+        if (deoptimizationRescueSlot != null && stub == null) {
+            crb.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
+        }
+
+        if (stub != null) {
+            Set<Register> definedRegisters = gatherDefinedRegisters(lir);
+            updateStub(stub, definedRegisters, gen.getCalleeSaveInfo(), frameMap);
+        }
+        return crb;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+        AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm;
+        FrameMap frameMap = crb.frameMap;
+        RegisterConfig regConfig = frameMap.getRegisterConfig();
+        HotSpotVMConfig config = config();
+        Label verifiedStub = new Label();
+
+        emitCodePrefix(crb, installedCodeOwner, masm, regConfig, config, verifiedStub);
+        emitCodeBody(crb, lir);
+        emitCodeSuffix(crb, masm, config, frameMap);
+    }
+
+    private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedStub) {
+        HotSpotProviders providers = getProviders();
+        if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
+            crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+            CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
+            // See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp
+            // equal to scratch(1) careful!
+            Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister;
+            Register receiver = asRegister(cc.getArgument(0));
+            int transferSize = config.useCompressedClassPointers ? 4 : 8;
+            AArch64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize);
+
+            // Are r10 and r11 available scratch registers here? One would hope so.
+            Register klass = r10;
+            if (config.useCompressedClassPointers) {
+                masm.ldr(32, klass, klassAddress);
+                AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding());
+            } else {
+                masm.ldr(64, klass, klassAddress);
+            }
+            masm.cmp(64, inlineCacheKlass, klass);
+            // conditional jumps have a much lower range than unconditional ones, which can be a
+            // problem because
+            // the miss handler could be out of range.
+            masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub);
+            AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER));
+        }
+        masm.align(config.codeEntryAlignment);
+        crb.recordMark(config.MARKID_OSR_ENTRY);
+        masm.bind(verifiedStub);
+        crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+    }
+
+    private static void emitCodeBody(CompilationResultBuilder crb, LIR lir) {
+        crb.emit(lir);
+    }
+
+    private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, HotSpotVMConfig config, FrameMap frameMap) {
+        HotSpotProviders providers = getProviders();
+        HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+        if (!frameContext.isStub) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
+                crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+                ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
+                Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+
+                crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+                linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
+                helper = AArch64Call.isNearCall(linkage) ? null : scratch;
+                AArch64Call.directCall(crb, masm, linkage, helper, null);
+            }
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+            assert !frameMap.accessesCallerFrame();
+        }
+    }
+
+    @Override
+    public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+        RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+        return new AArch64HotSpotRegisterAllocationConfig(registerConfigNonNull);
+    }
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,189 @@
+/*
+ * 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.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.inittimer.InitTimer.timer;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.inittimer.InitTimer;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.runtime.JVMCIBackend;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.compiler.aarch64.AArch64AddressLowering;
+import com.oracle.graal.compiler.aarch64.AArch64SuitesProvider;
+import com.oracle.graal.hotspot.DefaultHotSpotGraalCompilerFactory;
+import com.oracle.graal.hotspot.HotSpotBackend;
+import com.oracle.graal.hotspot.HotSpotBackendFactory;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.HotSpotReplacementsImpl;
+import com.oracle.graal.hotspot.meta.HotSpotForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotGraalConstantReflectionProvider;
+import com.oracle.graal.hotspot.meta.HotSpotGraphBuilderPlugins;
+import com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotLoweringProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.meta.HotSpotRegisters;
+import com.oracle.graal.hotspot.meta.HotSpotRegistersProvider;
+import com.oracle.graal.hotspot.meta.HotSpotSnippetReflectionProvider;
+import com.oracle.graal.hotspot.meta.HotSpotStampProvider;
+import com.oracle.graal.hotspot.meta.HotSpotSuitesProvider;
+import com.oracle.graal.hotspot.word.HotSpotWordTypes;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.phases.tiers.CompilerConfiguration;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.replacements.aarch64.AArch64GraphBuilderPlugins;
+import com.oracle.graal.serviceprovider.ServiceProvider;
+import com.oracle.graal.word.WordTypes;
+
+@ServiceProvider(HotSpotBackendFactory.class)
+public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
+
+    @Override
+    public void register() {
+        DefaultHotSpotGraalCompilerFactory.registerBackend(AArch64.class, this);
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotBackend host) {
+        assert host == null;
+
+        JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
+        HotSpotVMConfig config = jvmciRuntime.getConfig();
+        HotSpotProviders providers;
+        HotSpotRegistersProvider registers;
+        HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache();
+        TargetDescription target = codeCache.getTarget();
+        HotSpotConstantReflectionProvider constantReflection = new HotSpotGraalConstantReflectionProvider(jvmciRuntime);
+        HotSpotHostForeignCallsProvider foreignCalls;
+        Value[] nativeABICallerSaveRegisters;
+        HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess();
+        HotSpotLoweringProvider lowerer;
+        HotSpotSnippetReflectionProvider snippetReflection;
+        HotSpotReplacementsImpl replacements;
+        HotSpotSuitesProvider suites;
+        HotSpotWordTypes wordTypes;
+        Plugins plugins;
+        try (InitTimer t = timer("create providers")) {
+            try (InitTimer rt = timer("create HotSpotRegisters provider")) {
+                registers = createRegisters();
+            }
+            try (InitTimer rt = timer("create NativeABICallerSaveRegisters")) {
+                nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig());
+            }
+            try (InitTimer rt = timer("create ForeignCalls provider")) {
+                foreignCalls = createForeignCalls(jvmciRuntime, graalRuntime, metaAccess, codeCache, nativeABICallerSaveRegisters);
+            }
+            try (InitTimer rt = timer("create Lowerer provider")) {
+                lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, target);
+            }
+            HotSpotStampProvider stampProvider = new HotSpotStampProvider();
+            Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, stampProvider);
+
+            try (InitTimer rt = timer("create WordTypes")) {
+                wordTypes = new HotSpotWordTypes(metaAccess, target.wordJavaKind);
+            }
+            try (InitTimer rt = timer("create SnippetReflection provider")) {
+                snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
+            }
+            try (InitTimer rt = timer("create Replacements provider")) {
+                replacements = createReplacements(config, p, snippetReflection);
+            }
+            try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
+                plugins = createGraphBuilderPlugins(config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                replacements.setGraphBuilderPlugins(plugins);
+            }
+            try (InitTimer rt = timer("create Suites provider")) {
+                suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, codeCache);
+            }
+            providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, suites, registers, snippetReflection, wordTypes, plugins);
+        }
+        try (InitTimer rt = timer("instantiate backend")) {
+            return createBackend(config, graalRuntime, providers);
+        }
+    }
+
+    protected Plugins createGraphBuilderPlugins(HotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls,
+                    HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes,
+                    HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        AArch64GraphBuilderPlugins.register(plugins, foreignCalls);
+        return plugins;
+    }
+
+    protected AArch64HotSpotBackend createBackend(HotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+        return new AArch64HotSpotBackend(config, runtime, providers);
+    }
+
+    protected HotSpotRegistersProvider createRegisters() {
+        return new HotSpotRegisters(AArch64HotSpotRegisterConfig.threadRegister, AArch64HotSpotRegisterConfig.heapBaseRegister, sp);
+    }
+
+    protected HotSpotReplacementsImpl createReplacements(HotSpotVMConfig config, Providers p, SnippetReflectionProvider snippetReflection) {
+        return new HotSpotReplacementsImpl(p, snippetReflection, config, p.getCodeCache().getTarget());
+    }
+
+    protected HotSpotHostForeignCallsProvider createForeignCalls(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotCodeCacheProvider codeCache, Value[] nativeABICallerSaveRegisters) {
+        return new AArch64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
+    }
+
+    protected HotSpotSuitesProvider createSuites(HotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, CodeCacheProvider codeCache) {
+        return new HotSpotSuitesProvider(new AArch64SuitesProvider(compilerConfiguration, plugins), config, runtime, new AArch64AddressLowering(codeCache));
+    }
+
+    protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) {
+        return new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
+    }
+
+    protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
+                    HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") HotSpotVMConfig config, RegisterConfig regConfig) {
+        AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig;
+        Register[] callerSavedRegisters = conf.getCallerSaveRegisters();
+        Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.length];
+        for (int i = 0; i < callerSavedRegisters.length; i++) {
+            nativeABICallerSaveRegisters[i] = callerSavedRegisters[i].asValue();
+        }
+        return nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public String toString() {
+        return "AArch64";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,56 @@
+/*
+ * 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.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+
+@Opcode("CRUNTIME_CALL_EPILOGUE")
+public class AArch64HotSpotCRuntimeCallEpilogueOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallEpilogueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final int threadLastJavaFpOffset;
+    private final Register thread;
+
+    public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // reset last Java frame:
+        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
+        masm.str(64, zr, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+@Opcode
+public class AArch64HotSpotCRuntimeCallPrologueOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallPrologueOp.class);
+
+    private final int threadLastJavaSpOffset;
+    private final Register thread;
+    @Temp({REG}) protected AllocatableValue spScratch;
+
+    public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, AllocatableValue spScratch) {
+        super(TYPE);
+        this.threadLastJavaSpOffset = threadLastJavaSpOffset;
+        this.thread = thread;
+        this.spScratch = spScratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // save last Java frame
+        // We cannot save the SP directly so use a temporary register.
+        Register scratchRegister = asRegister(spScratch);
+        masm.movx(scratchRegister, sp);
+        masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+
+import static com.oracle.graal.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+public class AArch64HotSpotDeoptimizeCallerOp extends AArch64HotSpotEpilogueOp {
+    public static final LIRInstructionClass<AArch64HotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeCallerOp.class);
+
+    public AArch64HotSpotDeoptimizeCallerOp(HotSpotVMConfig config) {
+        super(TYPE, config);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+        AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.aarch64.AArch64BlockEndOp;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import static com.oracle.graal.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
+
+@Opcode("DEOPT")
+public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+    public static final LIRInstructionClass<AArch64HotSpotDeoptimizeOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDeoptimizeOp.class);
+    @State private LIRFrameState info;
+
+    public AArch64HotSpotDeoptimizeOp(LIRFrameState info) {
+        super(TYPE);
+        this.info = info;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotDirectStaticCallOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,69 @@
+/*
+ * 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.aarch64;
+
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64Call.DirectCallOp;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class AArch64HotSpotDirectStaticCallOp extends DirectCallOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDirectStaticCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final HotSpotVMConfig config;
+
+    public AArch64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isDirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        // For the first invocation this is set to a bitpattern that is guaranteed to never be a
+        // valid object which causes the called function to call a handler that installs the
+        // correct inline cache value here.
+        crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
+        masm.forceMov(inlineCacheRegister, config.nonOopBits);
+        super.emitCode(crb, masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotDirectVirtualCallOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,69 @@
+/*
+ * 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.aarch64;
+
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64Call.DirectCallOp;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A direct call that complies with the conventions for such calls in HotSpot. In particular, for
+ * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call.
+ */
+@Opcode("CALL_DIRECT")
+final class AArch64HotSpotDirectVirtualCallOp extends DirectCallOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(AArch64HotSpotDirectVirtualCallOp.class);
+
+    private final InvokeKind invokeKind;
+    private final HotSpotVMConfig config;
+
+    public AArch64HotSpotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
+        super(TYPE, target, result, parameters, temps, state);
+        assert invokeKind.isIndirect();
+        this.invokeKind = invokeKind;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        // The mark for an invocation that uses an inline cache must be placed at the
+        // instruction that loads the Klass from the inline cache.
+        // For the first invocation this is set to a bitpattern that is guaranteed to never be a
+        // valid object which causes the called function to call a handler that installs the
+        // correct inline cache value here.
+        crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
+        masm.forceMov(inlineCacheRegister, config.nonOopBits);
+        super.emitCode(crb, masm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotEpilogueOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,54 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.aarch64.AArch64BlockEndOp;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+
+abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+
+    private final HotSpotVMConfig config;
+
+    protected AArch64HotSpotEpilogueOp(LIRInstructionClass<? extends StandardOp.AbstractBlockEndOp> c, HotSpotVMConfig config) {
+        super(c);
+        this.config = config;
+    }
+
+    protected void leaveFrame(CompilationResultBuilder crb, AArch64MacroAssembler masm, boolean emitSafepoint) {
+        assert crb.frameContext != null : "We never elide frames in aarch64";
+        crb.frameContext.leave(crb);
+        if (emitSafepoint) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
+                Register scratch = sc.getRegister();
+                AArch64HotSpotSafepointOp.emitCode(crb, masm, config, true, scratch, null);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,95 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.PreferGraalStubs;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
+import static com.oracle.graal.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32;
+import static jdk.vm.ci.aarch64.AArch64.r0;
+import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.code.CallingConvention.Type.NativeCall;
+import static jdk.vm.ci.meta.LocationIdentity.any;
+import static jdk.vm.ci.meta.Value.ILLEGAL;
+
+import com.oracle.graal.hotspot.HotSpotBackend;
+import com.oracle.graal.hotspot.HotSpotForeignCallLinkageImpl;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.meta.HotSpotHostForeignCallsProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+public class AArch64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider {
+
+    private final Value[] nativeABICallerSaveRegisters;
+
+    public AArch64HotSpotForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache,
+                    Value[] nativeABICallerSaveRegisters) {
+        super(jvmciRuntime, runtime, metaAccess, codeCache);
+        this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters;
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers) {
+        HotSpotVMConfig config = jvmciRuntime.getConfig();
+        TargetDescription target = providers.getCodeCache().getTarget();
+        PlatformKind word = target.arch.getWordKind();
+
+        // The calling convention for the exception handler stub is (only?) defined in
+        // TemplateInterpreterGenerator::generate_throw_exception()
+        RegisterValue exception = r0.asValue(LIRKind.reference(word));
+        RegisterValue exceptionPc = r3.asValue(LIRKind.value(word));
+        CallingConvention exceptionCc = new CallingConvention(0, ILLEGAL, exception, exceptionPc);
+        register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF, null, exceptionCc, NOT_REEXECUTABLE, any()));
+        register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF, exceptionCc, null, NOT_REEXECUTABLE, any()));
+
+        if (PreferGraalStubs.getValue()) {
+            throw JVMCIError.unimplemented("PreferGraalStubs");
+        }
+
+        // These stubs do callee saving
+        if (config.useCRC32Intrinsics) {
+            registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, PRESERVES_REGISTERS, LEAF, NOT_REEXECUTABLE, any());
+        }
+
+        super.initialize(providers);
+    }
+
+    @Override
+    public Value[] getNativeABICallerSaveRegisters() {
+        return nativeABICallerSaveRegisters;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.sp;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+public class AArch64HotSpotJumpToExceptionHandlerInCallerOp extends AArch64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(AArch64HotSpotJumpToExceptionHandlerInCallerOp.class);
+
+    @Use(REG) private AllocatableValue handlerInCallerPc;
+    @Use(REG) private AllocatableValue exception;
+    @Use(REG) private AllocatableValue exceptionPc;
+    private final Register thread;
+    private final int isMethodHandleReturnOffset;
+
+    public AArch64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset,
+                    Register thread, HotSpotVMConfig config) {
+        super(TYPE, config);
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+        this.isMethodHandleReturnOffset = isMethodHandleReturnOffset;
+        this.thread = thread;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+
+        // Restore sp from fp if the exception PC is a method handle call site.
+        try (ScratchRegister sc = masm.getScratchRegister()) {
+            Register scratch = sc.getRegister();
+            AArch64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, /* allowOverwrite */false);
+            masm.ldr(32, scratch, address);
+            Label noRestore = new Label();
+            masm.cbz(32, scratch, noRestore);
+            masm.mov(64, sp, fp);
+            masm.bind(noRestore);
+        }
+        masm.jmp(asRegister(handlerInCallerPc));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotLIRGenerationResult.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,73 @@
+/*
+ * 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.hotspot.aarch64;
+
+import java.util.Map;
+
+import com.oracle.graal.compiler.common.CollectionsFactory;
+import com.oracle.graal.hotspot.stubs.Stub;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.framemap.FrameMapBuilder;
+import com.oracle.graal.lir.gen.LIRGenerationResultBase;
+
+import jdk.vm.ci.code.StackSlot;
+
+public class AArch64HotSpotLIRGenerationResult extends LIRGenerationResultBase {
+    /**
+     * The slot reserved for storing the original return address when a frame is marked for
+     * deoptimization. The return address slot in the callee is overwritten with the address of a
+     * deoptimization stub.
+     */
+    private StackSlot deoptimizationRescueSlot;
+    private final Object stub;
+
+    /**
+     * Map from debug infos that need to be updated with callee save information to the operations
+     * that provide the information.
+     */
+    private final Map<LIRFrameState, StandardOp.SaveRegistersOp> calleeSaveInfo = CollectionsFactory.newMap();
+
+    public AArch64HotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
+        super(compilationUnitName, lir, frameMapBuilder);
+        this.stub = stub;
+    }
+
+    StackSlot getDeoptimizationRescueSlot() {
+        return deoptimizationRescueSlot;
+    }
+
+    public final void setDeoptimizationRescueSlot(StackSlot stackSlot) {
+        this.deoptimizationRescueSlot = stackSlot;
+    }
+
+    Stub getStub() {
+        return (Stub) stub;
+    }
+
+    Map<LIRFrameState, StandardOp.SaveRegistersOp> getCalleeSaveInfo() {
+        return calleeSaveInfo;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,206 @@
+/*
+ * 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.hotspot.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.compiler.aarch64.AArch64ArithmeticLIRGenerator;
+import com.oracle.graal.compiler.aarch64.AArch64LIRGenerator;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.compiler.common.spi.LIRKindTool;
+import com.oracle.graal.hotspot.HotSpotBackend;
+import com.oracle.graal.hotspot.HotSpotLIRGenerator;
+import com.oracle.graal.hotspot.HotSpotLockStack;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.stubs.Stub;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.VirtualStackSlot;
+import com.oracle.graal.lir.aarch64.AArch64AddressValue;
+import com.oracle.graal.lir.aarch64.AArch64Move;
+import com.oracle.graal.lir.gen.LIRGenerationResult;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * LIR generator specialized for AArch64 HotSpot.
+ */
+public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator {
+
+    final HotSpotVMConfig config;
+    private HotSpotLockStack lockStack;
+
+    protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
+        this(providers, config, cc, lirGenRes, new ConstantTableBaseProvider());
+    }
+
+    private AArch64HotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        this(new AArch64HotSpotLIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(providers.getCodeCache(), constantTableBaseProvider), providers, config, cc,
+                        lirGenRes, constantTableBaseProvider);
+    }
+
+    protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, HotSpotVMConfig config,
+                    CallingConvention cc, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
+        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, cc, lirGenRes, constantTableBaseProvider);
+        this.config = config;
+    }
+
+    @Override
+    public boolean needOnlyOopMaps() {
+        // Stubs only need oop maps
+        return ((AArch64HotSpotLIRGenerationResult) getResult()).getStub() != null;
+    }
+
+    @Override
+    public HotSpotProviders getProviders() {
+        return (HotSpotProviders) super.getProviders();
+    }
+
+    @Override
+    public void emitTailcall(Value[] args, Value address) {
+        throw JVMCIError.unimplemented();
+    }
+
+    @Override
+    public SaveRegistersOp emitSaveAllRegisters() {
+        throw JVMCIError.unimplemented();
+    }
+
+    @Override
+    public VirtualStackSlot getLockSlot(int lockDepth) {
+        return getLockStack().makeLockSlot(lockDepth);
+    }
+
+    private HotSpotLockStack getLockStack() {
+        assert lockStack != null;
+        return lockStack;
+    }
+
+    protected void setLockStack(HotSpotLockStack lockStack) {
+        assert this.lockStack == null;
+        this.lockStack = lockStack;
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    public Value emitCompress(Value pointer, HotSpotVMConfig.CompressEncoding encoding, boolean nonNull) {
+        LIRKind inputKind = pointer.getLIRKind();
+        assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
+        Variable result = newVariable(LIRKind.reference(AArch64Kind.DWORD));
+        AllocatableValue base = getCompressionBase(encoding, inputKind);
+        // TODO (das) continue here.
+        throw JVMCIError.unimplemented("finish implementation");
+    }
+
+    private AllocatableValue getCompressionBase(HotSpotVMConfig.CompressEncoding encoding, LIRKind inputKind) {
+        if (inputKind.isReference(0)) {
+            // oop
+            return getProviders().getRegisters().getHeapBaseRegister().asValue();
+        } else {
+            // metaspace pointer
+            if (encoding.base == 0) {
+                return AArch64.zr.asValue(LIRKind.value(AArch64Kind.QWORD));
+            } else {
+                return emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.base));
+            }
+        }
+    }
+
+    @Override
+    public Value emitUncompress(Value pointer, HotSpotVMConfig.CompressEncoding encoding, boolean nonNull) {
+        return null;
+    }
+
+    @Override
+    public void emitPrefetchAllocate(Value address) {
+        // TODO (das) Optimization for later.
+    }
+
+    @Override
+    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
+        Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
+        Value nullValue = emitConstant(LIRKind.reference(AArch64Kind.QWORD), JavaConstant.NULL_POINTER);
+        moveDeoptValuesToThread(actionAndReason, nullValue);
+        append(new AArch64HotSpotDeoptimizeCallerOp(config));
+    }
+
+    @Override
+    public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
+        moveDeoptValuesToThread(actionAndReason, failedSpeculation);
+        append(new AArch64HotSpotDeoptimizeOp(state));
+    }
+
+    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
+        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
+        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
+    }
+
+    private void moveValueToThread(Value value, int offset) {
+        LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
+        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
+        AArch64AddressValue pendingDeoptAddress = new AArch64AddressValue(value.getLIRKind(), thread, Value.ILLEGAL, offset, false, AArch64Address.AddressingMode.IMMEDIATE_UNSCALED);
+        append(new AArch64Move.StoreOp((AArch64Kind) value.getPlatformKind(), pendingDeoptAddress, loadReg(value), null));
+    }
+
+    @Override
+    public void emitUnwind(Value exception) {
+        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
+        emitMove(exceptionParameter, exception);
+        append(new AArch64HotSpotUnwindOp(config, exceptionParameter));
+    }
+
+    @Override
+    public void emitReturn(JavaKind kind, Value input) {
+        AllocatableValue operand = Value.ILLEGAL;
+        if (input != null) {
+            operand = resultOperandFor(kind, input.getLIRKind());
+            emitMove(operand, input);
+        }
+        append(new AArch64HotSpotReturnOp(operand, getStub() != null, config));
+    }
+
+    /**
+     * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
+     * being generated.
+     */
+    public Stub getStub() {
+        return ((AArch64HotSpotLIRGenerationResult) getResult()).getStub();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotLIRKindTool.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,40 @@
+/*
+ * 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.hotspot.aarch64;
+
+import com.oracle.graal.compiler.aarch64.AArch64LIRKindTool;
+import com.oracle.graal.hotspot.nodes.type.HotSpotLIRKindTool;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.meta.LIRKind;
+
+public class AArch64HotSpotLIRKindTool extends AArch64LIRKindTool implements HotSpotLIRKindTool {
+
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(AArch64Kind.DWORD);
+    }
+
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(AArch64Kind.DWORD);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotLoweringProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,74 @@
+/*
+ * 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
+ * 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.aarch64;
+
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
+import com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider;
+import com.oracle.graal.hotspot.meta.HotSpotProviders;
+import com.oracle.graal.hotspot.meta.HotSpotRegistersProvider;
+import com.oracle.graal.nodes.calc.ConvertNode;
+import com.oracle.graal.nodes.calc.FixedBinaryNode;
+import com.oracle.graal.nodes.calc.RemNode;
+import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.replacements.aarch64.AArch64FloatArithmeticSnippets;
+import com.oracle.graal.replacements.aarch64.AArch64IntegerArithmeticSnippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class AArch64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
+
+    private AArch64IntegerArithmeticSnippets integerArithmeticSnippets;
+    private AArch64FloatArithmeticSnippets floatArithmeticSnippets;
+
+    public AArch64HotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
+                    HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
+        super(runtime, metaAccess, foreignCalls, registers, constantReflection, target);
+    }
+
+    @Override
+    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
+        integerArithmeticSnippets = new AArch64IntegerArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
+        floatArithmeticSnippets = new AArch64FloatArithmeticSnippets(providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
+        super.initialize(providers, config);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof FixedBinaryNode) {
+            integerArithmeticSnippets.lower((FixedBinaryNode) n, tool);
+        } else if (n instanceof RemNode) {
+            floatArithmeticSnippets.lower((RemNode) n, tool);
+        } else if (n instanceof ConvertNode) {
+            // AMD64 has custom lowerings for ConvertNodes, HotSpotLoweringProvider does not expect
+            // to see a ConvertNode and throws an error, just do nothing here.
+        } else {
+            super.lower(n, tool);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotMove.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,158 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotVMConfig.CompressEncoding;
+import jdk.vm.ci.meta.AllocatableValue;
+
+public class AArch64HotSpotMove {
+
+    /**
+     * Compresses a 8-byte pointer as a 4-byte int.
+     */
+    public static class CompressPointer extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register resultRegister = asRegister(result);
+            Register ptr = asRegister(input);
+            Register base = asRegister(baseRegister);
+            // result = (ptr - base) >> shift
+            if (encoding.base == 0) {
+                if (encoding.shift == 0) {
+                    masm.movx(resultRegister, ptr);
+                } else {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.lshr(64, resultRegister, ptr, encoding.shift);
+                }
+            } else if (nonNull) {
+                masm.sub(64, resultRegister, ptr, base);
+                if (encoding.shift != 0) {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.shl(64, resultRegister, resultRegister, encoding.shift);
+                }
+            } else {
+                // if ptr is null it still has to be null after compression
+                masm.cmp(64, ptr, 0);
+                masm.cmov(64, resultRegister, ptr, base, AArch64Assembler.ConditionFlag.NE);
+                masm.sub(64, resultRegister, resultRegister, base);
+                if (encoding.shift != 0) {
+                    assert encoding.alignment == encoding.shift : "Encode algorithm is wrong";
+                    masm.lshr(64, resultRegister, resultRegister, encoding.shift);
+                }
+            }
+        }
+    }
+
+    /**
+     * Decompresses a 4-byte offset into an actual pointer.
+     */
+    public static class UncompressPointer extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+
+        private final CompressEncoding encoding;
+        private final boolean nonNull;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue input;
+        @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
+
+        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register ptr = asRegister(input);
+            Register resultRegister = asRegister(result);
+            Register base = asRegister(baseRegister);
+            // result = base + (ptr << shift)
+            if (nonNull) {
+                assert encoding.shift == encoding.alignment;
+                masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.ASR, encoding.shift);
+            } else {
+                // if ptr is null it has to be null after decompression
+                // masm.cmp(64, );
+            }
+
+        }
+    }
+
+    //
+    // private static void decompressPointer(CompilationResultBuilder crb, ARMv8MacroAssembler masm,
+    // Register result,
+    // Register ptr, long base, int shift, int alignment) {
+    // assert base != 0 || shift == 0 || alignment == shift;
+    // // result = heapBase + ptr << alignment
+    // Register heapBase = ARMv8.heapBaseRegister;
+    // // if result == 0, we make sure that it will still be 0 at the end, so that it traps when
+    // // loading storing a value.
+    // masm.cmp(32, ptr, 0);
+    // masm.add(64, result, heapBase, ptr, ARMv8Assembler.ExtendType.UXTX, alignment);
+    // masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE);
+    // }
+
+    public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, Register klassBase, CompressEncoding encoding) {
+        // result = klassBase + ptr << shift
+        if (encoding.shift != 0 || encoding.base != 0) {
+            // (shift != 0 -> shift == alignment) && (shift == 0 -> base == 0)
+            assert (encoding.shift == 0 || encoding.shift == encoding.alignment) && (encoding.shift != 0 || encoding.base == 0) : "Decode algorithm is wrong.";
+            masm.add(64, result, klassBase, ptr, AArch64Assembler.ExtendType.UXTX, encoding.shift);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotMoveFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,83 @@
+/*
+ * 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.hotspot.aarch64;
+
+import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL;
+import static jdk.vm.ci.meta.JavaConstant.INT_0;
+import static jdk.vm.ci.meta.JavaConstant.LONG_0;
+
+import com.oracle.graal.compiler.aarch64.AArch64LIRGenerator.ConstantTableBaseProvider;
+import com.oracle.graal.compiler.aarch64.AArch64MoveFactory;
+import com.oracle.graal.lir.LIRInstruction;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+public class AArch64HotSpotMoveFactory extends AArch64MoveFactory {
+
+    public AArch64HotSpotMoveFactory(CodeCacheProvider codeCache, ConstantTableBaseProvider constantTableBaseProvider) {
+        super(codeCache, constantTableBaseProvider);
+    }
+
+    @Override
+    public boolean canInlineConstant(JavaConstant c) {
+        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
+            return true;
+        } else if (c instanceof HotSpotObjectConstant) {
+            return false;
+        } else {
+            return super.canInlineConstant(c);
+        }
+    }
+
+    @Override
+    public LIRInstruction createLoad(AllocatableValue dst, Constant src) {
+        Constant usedSource;
+        if (COMPRESSED_NULL.equals(src)) {
+            usedSource = INT_0;
+        } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) {
+            usedSource = LONG_0;
+        } else {
+            usedSource = src;
+        }
+        if (usedSource instanceof HotSpotConstant) {
+            HotSpotConstant constant = (HotSpotConstant) usedSource;
+            if (constant.isCompressed()) {
+                // return new SPARCHotSpotMove.LoadHotSpotObjectConstantInline(constant, dst);
+                throw JVMCIError.unimplemented();
+            } else {
+                // return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst,
+                // constantTableBaseProvider.getConstantTableBase());
+                throw JVMCIError.unimplemented();
+            }
+        } else {
+            return super.createLoad(dst, usedSource);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,192 @@
+/*
+ * 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.hotspot.aarch64;
+
+import static com.oracle.graal.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCacheRegister;
+import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.metaspaceMethodRegister;
+
+import com.oracle.graal.compiler.aarch64.AArch64NodeLIRBuilder;
+import com.oracle.graal.compiler.aarch64.AArch64NodeMatchRules;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.compiler.gen.DebugInfoBuilder;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.hotspot.HotSpotDebugInfoBuilder;
+import com.oracle.graal.hotspot.HotSpotLockStack;
+import com.oracle.graal.hotspot.HotSpotNodeLIRBuilder;
+import com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode;
+import com.oracle.graal.hotspot.nodes.HotSpotDirectCallTargetNode;
+import com.oracle.graal.hotspot.nodes.HotSpotIndirectCallTargetNode;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.aarch64.AArch64Move.CompareAndSwap;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.DirectCallTargetNode;
+import com.oracle.graal.nodes.FullInfopointNode;
+import com.oracle.graal.nodes.IndirectCallTargetNode;
+import com.oracle.graal.nodes.ParameterNode;
+import com.oracle.graal.nodes.SafepointNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.spi.NodeValueMap;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.ValueUtil;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * LIR generator specialized for AArch64 HotSpot.
+ */
+public class AArch64HotSpotNodeLIRBuilder extends AArch64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
+
+    public AArch64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AArch64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
+        assert gen instanceof AArch64HotSpotLIRGenerator;
+        assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
+        ((AArch64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
+    }
+
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
+        HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AArch64Kind.QWORD));
+        return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack);
+    }
+
+    private AArch64HotSpotLIRGenerator getGen() {
+        return (AArch64HotSpotLIRGenerator) gen;
+    }
+
+    @Override
+    protected void emitPrologue(StructuredGraph graph) {
+        CallingConvention incomingArguments = gen.getCallingConvention();
+        Value[] params = new Value[incomingArguments.getArgumentCount() + 2];
+        for (int i = 0; i < incomingArguments.getArgumentCount(); i++) {
+            params[i] = incomingArguments.getArgument(i);
+            if (isStackSlot(params[i])) {
+                StackSlot slot = ValueUtil.asStackSlot(params[i]);
+                if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) {
+                    gen.getResult().getLIR().setHasArgInCallerFrame();
+                }
+            }
+        }
+        params[params.length - 2] = fp.asValue(LIRKind.value(AMD64Kind.QWORD));
+        params[params.length - 1] = lr.asValue(LIRKind.value(AMD64Kind.QWORD));
+
+        gen.emitIncomingValues(params);
+
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            Value paramValue = params[param.index()];
+            assert paramValue.getLIRKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())) : paramValue.getLIRKind() + " != " + param.stamp();
+            setResult(param, gen.emitMove(paramValue));
+        }
+    }
+
+    @Override
+    public void visitSafepointNode(SafepointNode i) {
+        LIRFrameState info = state(i);
+        Variable scratch = gen.newVariable(LIRKind.value(getGen().target().arch.getWordKind()));
+        append(new AArch64HotSpotSafepointOp(info, getGen().config, scratch));
+    }
+
+    @Override
+    protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind();
+        if (invokeKind.isIndirect()) {
+            append(new AArch64HotSpotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, config()));
+        } else {
+            assert invokeKind.isDirect();
+            HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
+            assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
+            append(new AArch64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, config()));
+        }
+    }
+
+    @Override
+    protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
+        Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod());
+        Value targetAddressSrc = operand(callTarget.computedAddress());
+        AllocatableValue metaspaceMethodDst = metaspaceMethodRegister.asValue(metaspaceMethodSrc.getLIRKind());
+        AllocatableValue targetAddressDst = inlineCacheRegister.asValue(targetAddressSrc.getLIRKind());
+        gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc);
+        gen.emitMove(targetAddressDst, targetAddressSrc);
+        append(new AArch64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, config()));
+    }
+
+    @Override
+    public void emitPatchReturnAddress(ValueNode address) {
+        throw JVMCIError.unimplemented();
+    }
+
+    @Override
+    public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
+        Variable handler = gen.load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
+        assert outgoingCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1);
+        gen.emitMove(exceptionFixed, operand(exception));
+        gen.emitMove(exceptionPcFixed, operand(exceptionPc));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        AArch64HotSpotJumpToExceptionHandlerInCallerOp op = new AArch64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed,
+                        getGen().config.threadIsMethodHandleReturnOffset, thread, config());
+        append(op);
+    }
+
+    @Override
+    public void visitFullInfopointNode(FullInfopointNode i) {
+        if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) {
+            Debug.log("Ignoring InfopointNode for AFTER_BCI");
+        } else {
+            super.visitFullInfopointNode(i);
+        }
+    }
+
+    @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        AllocatableValue cmpValue = gen.asAllocatable(operand(x.expectedValue()));
+        AllocatableValue newValue = gen.asAllocatable(operand(x.newValue()));
+        LIRKind kind = cmpValue.getLIRKind();
+        assert kind.equals(newValue.getLIRKind());
+
+        Variable result = gen.newVariable(newValue.getLIRKind());
+        Variable scratch = gen.newVariable(LIRKind.value(AArch64Kind.DWORD));
+        append(new CompareAndSwap(result, cmpValue, newValue, getGen().asAddressValue(operand(x.getAddress())), scratch));
+        setResult(x, result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,148 @@
+/*
+ * 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.hotspot.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.r0;
+import static jdk.vm.ci.aarch64.AArch64.r1;
+import static jdk.vm.ci.aarch64.AArch64.r10;
+import static jdk.vm.ci.aarch64.AArch64.r11;
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.aarch64.AArch64.r13;
+import static jdk.vm.ci.aarch64.AArch64.r14;
+import static jdk.vm.ci.aarch64.AArch64.r15;
+import static jdk.vm.ci.aarch64.AArch64.r16;
+import static jdk.vm.ci.aarch64.AArch64.r17;
+import static jdk.vm.ci.aarch64.AArch64.r18;
+import static jdk.vm.ci.aarch64.AArch64.r19;
+import static jdk.vm.ci.aarch64.AArch64.r2;
+import static jdk.vm.ci.aarch64.AArch64.r20;
+import static jdk.vm.ci.aarch64.AArch64.r21;
+import static jdk.vm.ci.aarch64.AArch64.r22;
+import static jdk.vm.ci.aarch64.AArch64.r23;
+import static jdk.vm.ci.aarch64.AArch64.r24;
+import static jdk.vm.ci.aarch64.AArch64.r25;
+import static jdk.vm.ci.aarch64.AArch64.r26;
+import static jdk.vm.ci.aarch64.AArch64.r27;
+import static jdk.vm.ci.aarch64.AArch64.r28;
+import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.aarch64.AArch64.r4;
+import static jdk.vm.ci.aarch64.AArch64.r5;
+import static jdk.vm.ci.aarch64.AArch64.r6;
+import static jdk.vm.ci.aarch64.AArch64.r7;
+import static jdk.vm.ci.aarch64.AArch64.r8;
+import static jdk.vm.ci.aarch64.AArch64.r9;
+import static jdk.vm.ci.aarch64.AArch64.v0;
+import static jdk.vm.ci.aarch64.AArch64.v1;
+import static jdk.vm.ci.aarch64.AArch64.v10;
+import static jdk.vm.ci.aarch64.AArch64.v11;
+import static jdk.vm.ci.aarch64.AArch64.v12;
+import static jdk.vm.ci.aarch64.AArch64.v13;
+import static jdk.vm.ci.aarch64.AArch64.v14;
+import static jdk.vm.ci.aarch64.AArch64.v15;
+import static jdk.vm.ci.aarch64.AArch64.v16;
+import static jdk.vm.ci.aarch64.AArch64.v17;
+import static jdk.vm.ci.aarch64.AArch64.v18;
+import static jdk.vm.ci.aarch64.AArch64.v19;
+import static jdk.vm.ci.aarch64.AArch64.v2;
+import static jdk.vm.ci.aarch64.AArch64.v20;
+import static jdk.vm.ci.aarch64.AArch64.v21;
+import static jdk.vm.ci.aarch64.AArch64.v22;
+import static jdk.vm.ci.aarch64.AArch64.v23;
+import static jdk.vm.ci.aarch64.AArch64.v24;
+import static jdk.vm.ci.aarch64.AArch64.v25;
+import static jdk.vm.ci.aarch64.AArch64.v26;
+import static jdk.vm.ci.aarch64.AArch64.v27;
+import static jdk.vm.ci.aarch64.AArch64.v28;
+import static jdk.vm.ci.aarch64.AArch64.v29;
+import static jdk.vm.ci.aarch64.AArch64.v3;
+import static jdk.vm.ci.aarch64.AArch64.v30;
+import static jdk.vm.ci.aarch64.AArch64.v31;
+import static jdk.vm.ci.aarch64.AArch64.v4;
+import static jdk.vm.ci.aarch64.AArch64.v5;
+import static jdk.vm.ci.aarch64.AArch64.v6;
+import static jdk.vm.ci.aarch64.AArch64.v7;
+import static jdk.vm.ci.aarch64.AArch64.v8;
+import static jdk.vm.ci.aarch64.AArch64.v9;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+
+public class AArch64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig {
+
+    // @formatter:off
+    static final Register[] registerAllocationOrder = {
+        r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
+        r8,  r9,  r10, r11, r12, r13, r14, r15,
+        r16, r17, r18, r19, r20, r21, r22, r23,
+        r24, r25, r26, r27, r28, /* r29, r30, r31 */
+
+        v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,
+        v8,  v9,  v10, v11, v12, v13, v14, v15,
+        v16, v17, v18, v19, v20, v21, v22, v23,
+        v24, v25, v26, v27, v28, v29, v30, v31
+    };
+    // @formatter:on
+
+    public AArch64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig) {
+        super(registerConfig);
+    }
+
+    @Override
+    protected Register[] initAllocatable(Register[] registers) {
+        BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().length);
+        for (Register reg : registers) {
+            regMap.set(reg.number);
+        }
+
+        ArrayList<Register> allocatableRegisters = new ArrayList<>(registers.length);
+        for (Register reg : registerAllocationOrder) {
+            if (regMap.get(reg.number)) {
+                allocatableRegisters.add(reg);
+            }
+        }
+
+        return super.initAllocatable(allocatableRegisters.toArray(new Register[allocatableRegisters.size()]));
+    }
+
+    @Override
+    protected AllocatableRegisters createAllocatableRegisters(Register[] registers) {
+        int min = Integer.MAX_VALUE;
+        int max = Integer.MIN_VALUE;
+        for (Register reg : registers) {
+            int number = reg.number;
+            if (number < min) {
+                min = number;
+            }
+            if (number > max) {
+                max = number;
+            }
+        }
+        assert min < max;
+        return new AllocatableRegisters(registers, min, max);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotReturnOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,69 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Returns from a function.
+ */
+@Opcode("RETURN")
+public final class AArch64HotSpotReturnOp extends AArch64HotSpotEpilogueOp {
+
+    public static final LIRInstructionClass<AArch64HotSpotReturnOp> TYPE = LIRInstructionClass.create(AArch64HotSpotReturnOp.class);
+
+    @Use({REG, ILLEGAL}) private Value result;
+    private final boolean isStub;
+
+    public AArch64HotSpotReturnOp(Value result, boolean isStub, HotSpotVMConfig config) {
+        super(TYPE, config);
+        assert validReturnValue(result);
+        this.result = result;
+        this.isStub = isStub;
+    }
+
+    private static boolean validReturnValue(Value result) {
+        if (result.equals(Value.ILLEGAL)) {
+            return true;
+        }
+        return asRegister(result).encoding == 0;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        final boolean emitSafepoint = !isStub;
+        leaveFrame(crb, masm, emitSafepoint);
+        masm.ret(lr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotSafepointOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,97 @@
+/*
+ * 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.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64LIRInstruction;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.InfopointReason;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Emits a safepoint poll.
+ */
+@Opcode("SAFEPOINT")
+public class AArch64HotSpotSafepointOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64HotSpotSafepointOp> TYPE = LIRInstructionClass.create(AArch64HotSpotSafepointOp.class);
+
+    @State protected LIRFrameState state;
+    @Temp protected AllocatableValue scratchValue;
+
+    private final HotSpotVMConfig config;
+
+    public AArch64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, AllocatableValue scratch) {
+        super(TYPE);
+        this.state = state;
+        this.config = config;
+        this.scratchValue = scratch;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register scratch = asRegister(scratchValue);
+        emitCode(crb, masm, config, false, scratch, state);
+    }
+
+    /**
+     * Conservatively checks whether we can load the safepoint polling address with a single ldr
+     * instruction or not.
+     *
+     * @return true if it is guaranteed that polling page offset will always fit into a 21-bit
+     *         signed integer, false otherwise.
+     */
+    private static boolean isPollingPageFar(HotSpotVMConfig config) {
+        final long pollingPageAddress = config.safepointPollingAddress;
+        return !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheLowBound) || !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheHighBound);
+    }
+
+    public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, HotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) {
+        int pos = masm.position();
+        if (isPollingPageFar(config)) {
+            crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+            masm.forceMov(scratch, config.safepointPollingAddress);
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            masm.ldr(32, zr, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+        } else {
+            crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_NEAR : config.MARKID_POLL_NEAR);
+            if (state != null) {
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            masm.ldr(32, zr, AArch64Address.createPcLiteralAddress(0));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64HotSpotUnwindOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,71 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
+import static jdk.vm.ci.aarch64.AArch64.lr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+
+/**
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
+ */
+@Opcode("UNWIND")
+public class AArch64HotSpotUnwindOp extends AArch64HotSpotEpilogueOp {
+    public static final LIRInstructionClass<AArch64HotSpotUnwindOp> TYPE = LIRInstructionClass.create(AArch64HotSpotUnwindOp.class);
+
+    @Use protected RegisterValue exception;
+
+    public AArch64HotSpotUnwindOp(HotSpotVMConfig config, RegisterValue exception) {
+        super(TYPE, config);
+        this.exception = exception;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        leaveFrame(crb, masm, /* emitSafepoint */false);
+
+        ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getOutgoingCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is in lr after frame leave)
+        Register returnAddress = asRegister(cc.getArgument(1));
+        masm.movx(returnAddress, lr);
+
+        AArch64Call.directJmp(crb, masm, linkage);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.aarch64/src/com/oracle/graal/hotspot/aarch64/AArch64IndirectCallOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,81 @@
+/*
+ * 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.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.aarch64.AArch64.r12;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.aarch64.AArch64Call;
+import com.oracle.graal.lir.aarch64.AArch64Call.IndirectCallOp;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * A register indirect call that complies with the extra conventions for such calls in HotSpot. In
+ * particular, the metaspace Method of the callee must be in r12 for the case where a vtable entry's
+ * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to
+ * be in r12.
+ */
+@Opcode("CALL_INDIRECT")
+final class AArch64IndirectCallOp extends IndirectCallOp {
+
+    public static final LIRInstructionClass<AArch64IndirectCallOp> TYPE = LIRInstructionClass.create(AArch64IndirectCallOp.class);
+
+    /**
+     * Vtable stubs expect the metaspace Method in r12.
+     */
+    public static final Register METHOD = r12;
+
+    @Use({REG}) private Value metaspaceMethod;
+
+    private final HotSpotVMConfig config;
+
+    public AArch64IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, HotSpotVMConfig config) {
+        super(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        this.metaspaceMethod = metaspaceMethod;
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        crb.recordMark(config.MARKID_INLINE_INVOKE);
+        Register callReg = asRegister(targetAddress);
+        assert !callReg.equals(METHOD);
+        AArch64Call.indirectCall(crb, masm, callReg, callTarget, state);
+    }
+
+    @Override
+    public void verify() {
+        super.verify();
+        assert asRegister(metaspaceMethod).equals(METHOD);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/CompressedNullCheckTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/CompressedNullCheckTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,8 +24,6 @@
 
 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import org.junit.Assert;
 import org.junit.Assume;
@@ -37,6 +35,8 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.IsNullNode;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 
 /**
  * Ensures that frame omission works in cases where it is expected to.
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -41,7 +41,6 @@
 import jdk.vm.ci.inittimer.InitTimer;
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.runtime.JVMCIBackend;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.amd64.AMD64SuitesProvider;
@@ -66,6 +65,7 @@
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.replacements.amd64.AMD64GraphBuilderPlugins;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.graal.word.WordTypes;
 
 @ServiceProvider(HotSpotBackendFactory.class)
@@ -202,15 +202,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -37,7 +37,6 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.runtime.JVMCIBackend;
-import jdk.vm.ci.service.ServiceProvider;
 import jdk.vm.ci.sparc.SPARC;
 
 import com.oracle.graal.compiler.sparc.SPARCAddressLowering;
@@ -63,6 +62,7 @@
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.replacements.sparc.SPARCGraphBuilderPlugins;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(HotSpotBackendFactory.class)
 public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -34,8 +34,6 @@
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import org.junit.Assert;
 import org.junit.Ignore;
@@ -54,6 +52,8 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.memory.FloatingReadNode;
 import com.oracle.graal.nodes.memory.ReadNode;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.tiers.Suites;
 import com.oracle.graal.phases.tiers.SuitesProvider;
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -43,7 +43,7 @@
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
         HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
-        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, new Config(null), 1, 5, null, null, false).compile();
+        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, new Config(null), 1, 5, null, null, true).compile();
         assert ExitVMOnException.getValue() == originalSetting;
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/LoadJavaMirrorWithKlassTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/LoadJavaMirrorWithKlassTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,8 +25,6 @@
 import java.util.Objects;
 
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import org.junit.Test;
 
@@ -34,6 +32,8 @@
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.tiers.Suites;
 
 public class LoadJavaMirrorWithKlassTest extends GraalCompilerTest {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Tue Jan 05 16:42:05 2016 -0800
@@ -143,7 +143,7 @@
             HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
             int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
             HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, jvmciEnv);
-            CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, false);
+            CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false);
             task.runCompilation();
         }
     }
@@ -160,7 +160,7 @@
             try (AllocSpy as = AllocSpy.open(methodName)) {
                 HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
                 HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, JVMCICompiler.INVOCATION_ENTRY_BCI, jvmciEnv);
-                CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, false);
+                CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false);
                 task.runCompilation();
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Jan 05 16:42:05 2016 -0800
@@ -49,7 +49,7 @@
 import jdk.vm.ci.hotspot.events.EventProvider.CompilationEvent;
 import jdk.vm.ci.hotspot.events.EventProvider.CompilerFailureEvent;
 import jdk.vm.ci.runtime.JVMCICompiler;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 import sun.misc.Unsafe;
 
 import com.oracle.graal.debug.Debug;
@@ -105,6 +105,8 @@
      */
     private final boolean installAsDefault;
 
+    private final boolean useProfilingInfo;
+
     static class Lazy {
         /**
          * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the
@@ -113,10 +115,11 @@
         static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean();
     }
 
-    public CompilationTask(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean installAsDefault) {
+    public CompilationTask(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault) {
         this.jvmciRuntime = jvmciRuntime;
         this.compiler = compiler;
         this.request = request;
+        this.useProfilingInfo = useProfilingInfo;
         this.installAsDefault = installAsDefault;
     }
 
@@ -192,7 +195,7 @@
             try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(getId()), true))) {
                 // Begin the compilation event.
                 compilationEvent.begin();
-                result = compiler.compile(method, entryBCI);
+                result = compiler.compile(method, entryBCI, useProfilingInfo);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             } finally {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Tue Jan 05 16:42:05 2016 -0800
@@ -53,6 +53,7 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -71,11 +72,6 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.ConstantPool;
 import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.options.OptionDescriptor;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-import jdk.vm.ci.options.OptionsParser;
-import jdk.vm.ci.options.OptionsParser.OptionConsumer;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCICompiler;
 
@@ -89,6 +85,11 @@
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.debug.internal.DebugScope;
 import com.oracle.graal.debug.internal.MemUseTrackerImpl;
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
+import com.oracle.graal.options.OptionsParser;
+import com.oracle.graal.options.OptionsParser.OptionConsumer;
 
 /**
  * This class implements compile-the-world functionality with JVMCI.
@@ -125,19 +126,17 @@
          */
         public Config(String options) {
             if (options != null) {
-                List<String> optionSettings = new ArrayList<>();
+                Map<String, String> optionSettings = new HashMap<>();
                 for (String optionSetting : options.split("\\s+|#")) {
                     if (optionSetting.charAt(0) == '-') {
-                        optionSettings.add(optionSetting.substring(1));
-                        optionSettings.add("false");
+                        optionSettings.put(optionSetting.substring(1), "false");
                     } else if (optionSetting.charAt(0) == '+') {
-                        optionSettings.add(optionSetting.substring(1));
-                        optionSettings.add("true");
+                        optionSettings.put(optionSetting.substring(1), "true");
                     } else {
                         OptionsParser.parseOptionSettingTo(optionSetting, optionSettings);
                     }
                 }
-                OptionsParser.parseOptions(optionSettings.toArray(new String[optionSettings.size()]), this, null, null);
+                OptionsParser.parseOptions(optionSettings, this, null, null);
             }
         }
 
@@ -228,7 +227,6 @@
         // ...but we want to see exceptions.
         config.putIfAbsent(PrintBailout, true);
         config.putIfAbsent(PrintStackTraceOnException, true);
-        config.putIfAbsent(HotSpotResolvedJavaMethod.Options.UseProfilingInformation, false);
     }
 
     public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler) {
@@ -285,6 +283,12 @@
         }
     }
 
+    public void printStackTrace(Throwable t) {
+        if (verbose) {
+            t.printStackTrace(TTY.out);
+        }
+    }
+
     @SuppressWarnings("unused")
     private static void dummy() {
     }
@@ -481,10 +485,12 @@
             HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
                             CompileTheWorld.class.getDeclaredMethod("dummy"));
             int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
-            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), false);
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, new HotSpotCompilationRequest(dummyMethod, entryBCI, 0L), useProfilingInfo, installAsDefault);
             task.runCompilation();
         } catch (NoSuchMethodException | SecurityException e1) {
-            e1.printStackTrace();
+            printStackTrace(e1);
         }
 
         /*
@@ -597,7 +603,7 @@
                         }
                     } catch (Throwable t) {
                         println("CompileTheWorld (%d) : Skipping %s %s", classFileCounter, className, t.toString());
-                        t.printStackTrace();
+                        printStackTrace(t);
                     }
                 }
                 cpe.close();
@@ -676,7 +682,10 @@
             long allocatedAtStart = MemUseTrackerImpl.getCurrentThreadAllocatedBytes();
             int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
             HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
-            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, false);
+            // For more stable CTW execution, disable use of profiling information
+            boolean useProfilingInfo = false;
+            boolean installAsDefault = false;
+            CompilationTask task = new CompilationTask(jvmciRuntime, compiler, request, useProfilingInfo, installAsDefault);
             task.runCompilation();
 
             memoryUsed.getAndAdd(MemUseTrackerImpl.getCurrentThreadAllocatedBytes() - allocatedAtStart);
@@ -685,7 +694,7 @@
         } catch (Throwable t) {
             // Catch everything and print a message
             println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
-            t.printStackTrace(TTY.out);
+            printStackTrace(t);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorldOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorldOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,11 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 /**
  * Options related to {@link CompileTheWorld}.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DefaultHotSpotGraalCompilerFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DefaultHotSpotGraalCompilerFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -26,10 +26,10 @@
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.compiler.phases.BasicCompilerConfiguration;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(JVMCICompilerFactory.class)
 public class DefaultHotSpotGraalCompilerFactory extends HotSpotGraalCompilerFactory {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/EconomyHotSpotGraalCompilerFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/EconomyHotSpotGraalCompilerFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -23,10 +23,10 @@
 package com.oracle.graal.hotspot;
 
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.compiler.phases.EconomyCompilerConfiguration;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(JVMCICompilerFactory.class)
 public class EconomyHotSpotGraalCompilerFactory extends DefaultHotSpotGraalCompilerFactory {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Jan 05 16:42:05 2016 -0800
@@ -37,9 +37,6 @@
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
@@ -67,6 +64,9 @@
 import com.oracle.graal.lir.framemap.FrameMap;
 import com.oracle.graal.lir.framemap.ReferenceMapBuilder;
 import com.oracle.graal.nodes.UnwindNode;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.tiers.SuitesProvider;
 import com.oracle.graal.word.Pointer;
 import com.oracle.graal.word.Word;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompiler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -33,10 +33,12 @@
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ProfilingInfo;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.SpeculationLog;
+import jdk.vm.ci.meta.TriState;
 import jdk.vm.ci.runtime.JVMCICompiler;
 
 import com.oracle.graal.api.runtime.GraalJVMCICompiler;
@@ -48,7 +50,6 @@
 import com.oracle.graal.debug.TopLevelDebugConfig;
 import com.oracle.graal.debug.internal.DebugScope;
 import com.oracle.graal.hotspot.meta.HotSpotProviders;
-import com.oracle.graal.hotspot.meta.HotSpotSuitesProvider;
 import com.oracle.graal.hotspot.phases.OnStackReplacementPhase;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.lir.asm.CompilationResultBuilderFactory;
@@ -56,8 +57,9 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.DebugInfoMode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext;
-import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.OptimisticOptimizations.Optimization;
@@ -88,7 +90,7 @@
             DebugEnvironment.initialize(TTY.out);
         }
 
-        CompilationTask task = new CompilationTask(jvmciRuntime, this, (HotSpotCompilationRequest) request, true);
+        CompilationTask task = new CompilationTask(jvmciRuntime, this, (HotSpotCompilationRequest) request, true, true);
         try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig())) {
             task.runCompilation();
         }
@@ -106,7 +108,7 @@
         System.exit(0);
     }
 
-    public CompilationResult compile(ResolvedJavaMethod method, int entryBCI) {
+    public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo) {
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
         final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
@@ -130,7 +132,7 @@
         }
         Suites suites = getSuites(providers);
         LIRSuites lirSuites = getLIRSuites(providers);
-        ProfilingInfo profilingInfo = method.getProfilingInfo(!isOSR, isOSR);
+        ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE);
         OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
         if (isOSR) {
             // In OSR compiles, we cannot rely on never executed code profiles, because
@@ -139,10 +141,11 @@
         }
         CompilationResult result = new CompilationResult();
         result.setEntryBCI(entryBCI);
-        GraalCompiler.compileGraph(graph, cc, method, providers, backend, getGraphBuilderSuite(providers, isOSR), optimisticOpts, profilingInfo, suites, lirSuites, result,
-                        CompilationResultBuilderFactory.Default);
+        boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
+        PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR, useProfilingInfo);
+        GraalCompiler.compileGraph(graph, cc, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, CompilationResultBuilderFactory.Default);
 
-        if (!isOSR) {
+        if (!isOSR && useProfilingInfo) {
             ProfilingInfo profile = method.getProfilingInfo();
             profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount());
         }
@@ -185,14 +188,46 @@
         return providers.getSuites().getDefaultLIRSuites();
     }
 
-    protected PhaseSuite<HighTierContext> getGraphBuilderSuite(HotSpotProviders providers, boolean isOSR) {
-        PhaseSuite<HighTierContext> suite = providers.getSuites().getDefaultGraphBuilderSuite();
-        if (providers.getCodeCache().shouldDebugNonSafepoints()) {
-            suite = HotSpotSuitesProvider.withSimpleDebugInfo(suite);
-        }
-        if (isOSR) {
-            suite = suite.copy();
-            suite.appendPhase(new OnStackReplacementPhase());
+    /**
+     * Reconfigures a given graph builder suite (GBS) if one of the given GBS parameter values is
+     * not the default.
+     *
+     * @param suite the graph builder suite
+     * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is
+     *            false)
+     * @param isOSR specifies if extra OSR-specific post-processing is required (default is false)
+     * @param useProfilingInfo specifies if the graph builder should use profiling info (default is
+     *            true)
+     * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a
+     *         default value otherwise {@code suite}
+     */
+    protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR, boolean useProfilingInfo) {
+        if (shouldDebugNonSafepoints || isOSR || !useProfilingInfo) {
+            PhaseSuite<HighTierContext> newGbs = suite.copy();
+
+            if (shouldDebugNonSafepoints || !useProfilingInfo) {
+                // This complexity below is to ensure exactly one
+                // GraphBuilderConfiguration copy is made.
+                GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
+                GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
+                if (shouldDebugNonSafepoints) {
+                    graphBuilderConfig = graphBuilderConfig.withDebugInfoMode(DebugInfoMode.Simple);
+                    if (!useProfilingInfo) {
+                        graphBuilderConfig.setUseProfiling(false);
+                    }
+                } else {
+                    assert !useProfilingInfo;
+                    graphBuilderConfig = graphBuilderConfig.copy();
+                    graphBuilderConfig.setUseProfiling(false);
+                }
+
+                GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
+                newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
+            }
+            if (isOSR) {
+                newGbs.appendPhase(new OnStackReplacementPhase());
+            }
+            return newGbs;
         }
         return suite;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompilerFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalCompilerFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -23,20 +23,37 @@
 package com.oracle.graal.hotspot;
 
 import static jdk.vm.ci.inittimer.InitTimer.timer;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
 import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.inittimer.InitTimer;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
 import jdk.vm.ci.runtime.JVMCIRuntime;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
+import sun.misc.VM;
 
+import com.oracle.graal.options.GraalJarsOptionDescriptorsProvider;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionsParser;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 
 public abstract class HotSpotGraalCompilerFactory implements JVMCICompilerFactory {
 
+    static {
+        initializeOptions();
+    }
+
     static class Options {
 
         // @formatter:off
@@ -62,6 +79,67 @@
         }
     }
 
+    /**
+     * Parses the options in the file denoted by the {@linkplain VM#getSavedProperty(String) saved}
+     * system property named {@code "graal.options.file"} if the file exists followed by the options
+     * encoded in saved system properties whose names start with {@code "graal.option."}. Key/value
+     * pairs are parsed from the file denoted by {@code "graal.options.file"} with
+     * {@link Properties#load(java.io.Reader)}.
+     */
+    @SuppressWarnings("try")
+    private static void initializeOptions() {
+        try (InitTimer t = timer("InitializeOptions")) {
+            boolean jdk8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+            GraalJarsOptionDescriptorsProvider odp = jdk8OrEarlier ? GraalJarsOptionDescriptorsProvider.create() : null;
+
+            String optionsFile = System.getProperty("graal.options.file");
+
+            if (optionsFile != null) {
+                File graalOptions = new File(optionsFile);
+                if (graalOptions.exists()) {
+                    try (FileReader fr = new FileReader(graalOptions)) {
+                        Properties props = new Properties();
+                        props.load(fr);
+                        Map<String, String> optionSettings = new HashMap<>();
+                        for (Map.Entry<Object, Object> e : props.entrySet()) {
+                            optionSettings.put((String) e.getKey(), (String) e.getValue());
+                        }
+                        try {
+                            OptionsParser.parseOptions(optionSettings, null, odp, null);
+                        } catch (Throwable e) {
+                            throw new InternalError("Error parsing an option from " + graalOptions, e);
+                        }
+                    } catch (IOException e) {
+                        throw new InternalError("Error reading " + graalOptions, e);
+                    }
+                }
+            }
+
+            Properties savedProps = getSavedProperties();
+
+            Map<String, String> optionSettings = new HashMap<>();
+            for (Map.Entry<Object, Object> e : savedProps.entrySet()) {
+                String name = (String) e.getKey();
+                if (name.startsWith("graal.option.")) {
+                    String value = (String) e.getValue();
+                    optionSettings.put(name.substring("graal.option.".length()), value);
+                }
+            }
+
+            OptionsParser.parseOptions(optionSettings, null, odp, null);
+        }
+    }
+
+    private static Properties getSavedProperties() {
+        try {
+            Field savedPropsField = VM.class.getDeclaredField("savedProps");
+            savedPropsField.setAccessible(true);
+            return (Properties) savedPropsField.get(null);
+        } catch (Exception e) {
+            throw new JVMCIError(e);
+        }
+    }
+
     protected abstract HotSpotBackendFactory getBackendFactory(Architecture arch);
 
     protected abstract CompilerConfiguration createCompilerConfiguration();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,9 +28,9 @@
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotVMEventListener;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.debug.Debug;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(HotSpotVMEventListener.class)
 public class HotSpotGraalVMEventListener implements HotSpotVMEventListener {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,7 +29,7 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.inittimer.InitTimer;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
 import com.oracle.graal.debug.Debug;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTTYStreamProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTTYStreamProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,11 +24,10 @@
 
 import java.io.PrintStream;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.service.ServiceProvider;
-
 import com.oracle.graal.debug.TTYStreamProvider;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(TTYStreamProvider.class)
 public class HotSpotTTYStreamProvider implements TTYStreamProvider {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/PrintStreamOption.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/PrintStreamOption.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,9 +29,10 @@
 import java.io.PrintStream;
 import java.lang.management.ManagementFactory;
 
+import com.oracle.graal.options.OptionValue;
+
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
-import jdk.vm.ci.options.OptionValue;
 
 /**
  * An option that encapsulates and configures a print stream.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Tue Jan 05 16:42:05 2016 -0800
@@ -39,13 +39,13 @@
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.inittimer.SuppressFBWarnings;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.hotspot.replacements.NewObjectSnippets;
 import com.oracle.graal.nodes.debug.DynamicCounterNode;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 //JaCoCo Exclude
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -332,7 +332,7 @@
         StructuredGraph graph = n.graph();
         assert !n.getHub().isConstant();
         AddressNode address = createOffsetAddress(graph, n.getHub(), config().klassLayoutHelperOffset);
-        graph.replaceFloating(n, graph.unique(new FloatingReadNode(address, KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)));
+        n.replaceAtUsagesAndDelete(graph.unique(new FloatingReadNode(address, KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)));
     }
 
     private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) {
@@ -344,7 +344,7 @@
         assert !n.getHub().isConstant();
         AddressNode address = createOffsetAddress(graph, n.getHub(), config().classMirrorOffset);
         FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
-        graph.replaceFloating(n, read);
+        n.replaceAtUsagesAndDelete(read);
     }
 
     private void lowerClassGetHubNode(ClassGetHubNode n, LoweringTool tool) {
@@ -356,7 +356,7 @@
         assert !n.getValue().isConstant();
         AddressNode address = createOffsetAddress(graph, n.getValue(), config().klassOffset);
         FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_KLASS_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
-        graph.replaceFloating(n, read);
+        n.replaceAtUsagesAndDelete(read);
     }
 
     private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
@@ -466,7 +466,7 @@
         StampProvider stampProvider = tool.getStampProvider();
         LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, getClass.getObject()));
         HubGetClassNode hubGetClass = graph.unique(new HubGetClassNode(tool.getMetaAccess(), hub));
-        graph.replaceFloating(getClass, hubGetClass);
+        getClass.replaceAtUsagesAndDelete(hubGetClass);
         hub.lower(tool);
         hubGetClass.lower(tool);
     }
@@ -510,8 +510,7 @@
                 osrLocal.replaceAndDelete(load);
                 graph.addBeforeFixed(migrationEnd, load);
             }
-            osrStart.replaceAtUsages(newStart);
-            osrStart.safeDelete();
+            osrStart.replaceAtUsagesAndDelete(newStart);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotDisassemblerProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotDisassemblerProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -26,9 +26,9 @@
 import jdk.vm.ci.code.CompilationResult;
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.code.DisassemblerProvider;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 /**
  * HotSpot implementation of {@link DisassemblerProvider}.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraalConstantReflectionProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraalConstantReflectionProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -35,13 +35,15 @@
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
 import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaField;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.runtime.JVMCI;
 
 import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
 import com.oracle.graal.replacements.ReplacementsImpl;
 import com.oracle.graal.replacements.SnippetCounter;
 import com.oracle.graal.replacements.SnippetTemplate;
@@ -49,7 +51,7 @@
 
 /**
  * Extends {@link HotSpotConstantReflectionProvider} to override the implementation of
- * {@link #readConstantFieldValue(JavaField, JavaConstant)} with Graal specific semantics.
+ * {@link #readConstantFieldValue(ResolvedJavaField, JavaConstant)} with Graal specific semantics.
  */
 public class HotSpotGraalConstantReflectionProvider extends HotSpotConstantReflectionProvider {
 
@@ -57,10 +59,24 @@
         super(runtime);
     }
 
+    private ResolvedJavaType cachedStableOptionValueType;
+
+    /**
+     * The {@code value} field in {@link OptionValue} is considered constant if {@code receiver} is
+     * a {@link StableOptionValue} instance.
+     */
     @Override
-    public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) {
+    public JavaConstant readConstantFieldValue(ResolvedJavaField field, JavaConstant receiver) {
         MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess();
         assert !ImmutableCode.getValue() || isCalledForSnippets(metaAccess) || SnippetGraphUnderConstruction.get() != null || FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver;
+        if (!field.isStatic() && field.getName().equals("value")) {
+            if (cachedStableOptionValueType == null) {
+                cachedStableOptionValueType = metaAccess.lookupJavaType(StableOptionValue.class);
+            }
+            if (cachedStableOptionValueType.isInstance(receiver)) {
+                return readFieldValue(field, receiver);
+            }
+        }
         return super.readConstantFieldValue(field, receiver);
     }
 
@@ -116,8 +132,8 @@
 
         /**
          * If the compiler is configured for AOT mode,
-         * {@link #readConstantFieldValue(JavaField, JavaConstant)} should be only called for
-         * snippets or replacements.
+         * {@link #readConstantFieldValue(ResolvedJavaField, JavaConstant)} should be only called
+         * for snippets or replacements.
          */
         static boolean isCalledForSnippets(MetaAccessProvider metaAccess) {
             assert ImmutableCode.getValue();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Jan 05 16:42:05 2016 -0800
@@ -38,8 +38,7 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.options.StableOptionValue;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 import sun.reflect.Reflection;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
@@ -74,6 +73,7 @@
 import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
 import com.oracle.graal.nodes.spi.StampProvider;
 import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.options.StableOptionValue;
 import com.oracle.graal.replacements.InlineDuringParsingPlugin;
 import com.oracle.graal.replacements.MethodHandlePlugin;
 import com.oracle.graal.replacements.NodeIntrinsificationPlugin;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,8 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.ImmutableCode;
 import static com.oracle.graal.compiler.common.GraalOptions.VerifyPhases;
 import jdk.vm.ci.hotspot.HotSpotVMConfig;
-import jdk.vm.ci.options.DerivedOptionValue;
-import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
 
 import com.oracle.graal.hotspot.HotSpotBackend;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
@@ -44,6 +42,8 @@
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.DebugInfoMode;
+import com.oracle.graal.options.DerivedOptionValue;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.AddressLoweringPhase;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,16 +22,16 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import sun.reflect.ConstantPool;
+import sun.reflect.Reflection;
+
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.nodes.spi.LoweringProvider;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.spi.ReplacementsProvider;
-
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.service.ServiceProvider;
-import sun.reflect.ConstantPool;
-import sun.reflect.Reflection;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(ReplacementsProvider.class)
 public class HotSpotSubstitutions implements ReplacementsProvider {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippetsOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippetsOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Options related to {@link InstanceOfSnippets}.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Tue Jan 05 16:42:05 2016 -0800
@@ -62,9 +62,6 @@
 import jdk.vm.ci.meta.LocationIdentity;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.api.replacements.Fold;
 import com.oracle.graal.compiler.common.spi.ForeignCallDescriptor;
@@ -99,6 +96,9 @@
 import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
 import com.oracle.graal.nodes.spi.LoweringTool;
 import com.oracle.graal.nodes.type.StampTool;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.replacements.Log;
 import com.oracle.graal.replacements.Snippet;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Jan 05 16:42:05 2016 -0800
@@ -204,7 +204,7 @@
         return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
-    @NodeIntrinsic(ForeignCallNode.class)
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
     public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 
     @Snippet
@@ -270,20 +270,20 @@
         return result;
     }
 
-    @NodeIntrinsic(ForeignCallNode.class)
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
     public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length, boolean fillContents);
 
     public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
     public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
 
-    @NodeIntrinsic(ForeignCallNode.class)
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
     public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
 
     public static Object dynamicNewInstanceStub(Class<?> elementType) {
         return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType);
     }
 
-    @NodeIntrinsic(ForeignCallNode.class)
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
     public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 
     @Snippet
@@ -342,7 +342,7 @@
         return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims);
     }
 
-    @NodeIntrinsic(ForeignCallNode.class)
+    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
     public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int rank, Word dims);
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippetsOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippetsOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Options related to {@link NewObjectSnippets}.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Tue Jan 05 16:42:05 2016 -0800
@@ -104,6 +104,7 @@
         Plugins plugins = new Plugins(defaultPlugins);
         plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(makeConstArgs(), metaAccess, providers.getSnippetReflection()));
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+        config.setUseProfiling(false);
 
         // Stubs cannot have optimistic assumptions since they have
         // to be valid for the entire run of the VM.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.emitBackEnd;
 import static com.oracle.graal.compiler.GraalCompiler.emitFrontEnd;
-import static com.oracle.graal.compiler.GraalCompiler.getProfilingInfo;
 import static com.oracle.graal.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
 
 import java.util.ListIterator;
@@ -41,7 +40,9 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
 
 import com.oracle.graal.compiler.target.Backend;
 import com.oracle.graal.debug.Debug;
@@ -58,7 +59,6 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.Suites;
 
 //JaCoCo Exclude
@@ -182,9 +182,9 @@
                 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
                     Suites defaultSuites = providers.getSuites().getDefaultSuites();
                     Suites suites = new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier());
-                    SchedulePhase schedule = emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), suites);
+                    emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites);
                     LIRSuites lirSuites = createLIRSuites();
-                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, schedule, getRegisterConfig(), lirSuites);
+                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites);
                     assert checkStubInvariants();
                 } catch (Throwable e) {
                     throw Debug.handle(e);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java	Tue Jan 05 16:42:05 2016 -0800
@@ -2464,7 +2464,6 @@
 
             lastInstr = firstInstruction;
             frameState = getEntryState(block, currentDimension);
-            frameState.cleanDeletedNodes();
             parser.setCurrentFrameState(frameState);
             currentBlock = block;
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParserOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParserOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.java;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.StableOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
 
 /**
  * Options related to {@link BytecodeParser}.
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.java;
 
-import jdk.vm.ci.options.DerivedOptionValue;
-import jdk.vm.ci.options.DerivedOptionValue.OptionSupplier;
-
 import com.oracle.graal.lir.phases.LIRSuites;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.options.DerivedOptionValue;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.tiers.CompilerConfiguration;
 import com.oracle.graal.phases.tiers.HighTierContext;
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,8 +31,6 @@
 import static com.oracle.graal.bytecode.Bytecodes.POP;
 import static com.oracle.graal.bytecode.Bytecodes.POP2;
 import static com.oracle.graal.bytecode.Bytecodes.SWAP;
-import static com.oracle.graal.graph.iterators.NodePredicates.isA;
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
 import static com.oracle.graal.java.BytecodeParserOptions.HideSubstitutionStates;
 import static com.oracle.graal.nodes.FrameState.TWO_SLOT_MARKER;
 import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere;
@@ -57,6 +55,7 @@
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.nodeinfo.Verbosity;
 import com.oracle.graal.nodes.AbstractMergeNode;
+import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.LoopBeginNode;
 import com.oracle.graal.nodes.LoopExitNode;
@@ -67,7 +66,6 @@
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
-import com.oracle.graal.nodes.ValueProxyNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.graphbuilderconf.ParameterPlugin;
 import com.oracle.graal.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState;
@@ -356,29 +354,6 @@
         return true;
     }
 
-    /**
-     * Phi nodes are recursively deleted in {@link #propagateDelete}. However, this does not cover
-     * frame state builder objects, since these are not nodes and not in the usage list of the phi
-     * node. Therefore, we clean the frame state builder manually here, before we parse a block.
-     */
-    public void cleanDeletedNodes() {
-        for (int i = 0; i < localsSize(); i++) {
-            ValueNode node = locals[i];
-            if (node != null && node.isDeleted()) {
-                assert node instanceof ValuePhiNode || node instanceof ValueProxyNode;
-                locals[i] = null;
-            }
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            ValueNode node = stack[i];
-            assert node == null || !node.isDeleted();
-        }
-        for (int i = 0; i < lockedObjects.length; i++) {
-            ValueNode node = lockedObjects[i];
-            assert !node.isDeleted();
-        }
-    }
-
     public void merge(AbstractMergeNode block, FrameStateBuilder other) {
         assert isCompatibleWith(other);
 
@@ -407,10 +382,12 @@
             return null;
         } else if (block.isPhiAtMerge(currentValue)) {
             if (otherValue == null || otherValue == TWO_SLOT_MARKER || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) {
-                propagateDelete((ValuePhiNode) currentValue);
-                return null;
+                // This phi must be dead anyway, add input of correct stack kind to keep the graph
+                // invariants.
+                ((PhiNode) currentValue).addInput(ConstantNode.defaultForKind(currentValue.getStackKind()));
+            } else {
+                ((PhiNode) currentValue).addInput(otherValue);
             }
-            ((PhiNode) currentValue).addInput(otherValue);
             return currentValue;
         } else if (currentValue != otherValue) {
             if (currentValue == TWO_SLOT_MARKER || otherValue == TWO_SLOT_MARKER) {
@@ -435,25 +412,6 @@
         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 inferPhiStamps(AbstractMergeNode block) {
         for (int i = 0; i < localsSize(); i++) {
             inferPhiStamp(block, locals[i]);
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/backend/ConstantPhiTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/backend/ConstantPhiTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,13 +27,12 @@
 
 import java.lang.reflect.Method;
 
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-
 import org.junit.Test;
 
 import com.oracle.graal.compiler.common.GraalOptions;
 import com.oracle.graal.jtt.JTTTest;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 
 public class ConstantPhiTest extends JTTTest {
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/backend/LargeConstantSectionTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/backend/LargeConstantSectionTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -34,8 +34,6 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Label;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -48,6 +46,8 @@
 import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.compiler.common.GraalOptions;
 import com.oracle.graal.jtt.JTTTest;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 
 public class LargeConstantSectionTest extends JTTTest {
     private static final String NAME = "LargeConstantSection";
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_instanceof01.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_instanceof01.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.jtt.bytecode;
 
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-
 import org.junit.Test;
 
 import com.oracle.graal.compiler.phases.HighTier;
 import com.oracle.graal.jtt.JTTTest;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.tiers.Suites;
 
 /**
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/LambdaEagerTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/LambdaEagerTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,14 +28,14 @@
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.DeoptimizationReason;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 
 import org.junit.Test;
 
 import com.oracle.graal.compiler.common.GraalOptions;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 
 public class LambdaEagerTest extends GraalCompilerTest {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64AddressValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,113 @@
+/*
+ * 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.lir.aarch64;
+
+import java.util.EnumSet;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.lir.CompositeValue;
+import com.oracle.graal.lir.InstructionValueConsumer;
+import com.oracle.graal.lir.InstructionValueProcedure;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+
+public final class AArch64AddressValue extends CompositeValue {
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
+    @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
+    @Component({OperandFlag.REG, OperandFlag.ILLEGAL}) protected AllocatableValue offset;
+    private final int immediate;
+    /**
+     * Whether register offset should be scaled or not.
+     */
+    private final boolean scaled;
+    private final AArch64Address.AddressingMode addressingMode;
+
+    public AArch64AddressValue(LIRKind kind, AllocatableValue base, AllocatableValue offset, int immediate, boolean scaled, AArch64Address.AddressingMode addressingMode) {
+        super(kind);
+        this.base = base;
+        this.offset = offset;
+        this.immediate = immediate;
+        this.scaled = scaled;
+        this.addressingMode = addressingMode;
+    }
+
+    private static Register toRegister(AllocatableValue value) {
+        if (value.equals(Value.ILLEGAL)) {
+            return AArch64.zr;
+        } else {
+            return ((RegisterValue) value).getRegister();
+        }
+    }
+
+    public AllocatableValue getBase() {
+        return base;
+    }
+
+    public AllocatableValue getOffset() {
+        return offset;
+    }
+
+    public int getImmediate() {
+        return immediate;
+    }
+
+    public boolean isScaled() {
+        return scaled;
+    }
+
+    public AArch64Address.AddressingMode getAddressingMode() {
+        return addressingMode;
+    }
+
+    public AArch64Address toAddress() {
+        Register baseReg = toRegister(base);
+        Register offsetReg = toRegister(offset);
+        AArch64Assembler.ExtendType extendType = addressingMode == AArch64Address.AddressingMode.EXTENDED_REGISTER_OFFSET ? AArch64Assembler.ExtendType.SXTW : null;
+        return AArch64Address.createAddress(addressingMode, baseReg, offsetReg, immediate, scaled, extendType);
+    }
+
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newOffset = (AllocatableValue) proc.doValue(inst, offset, mode, flags);
+        if (!base.identityEquals(newBase) || !offset.identityEquals(newOffset)) {
+            return new AArch64AddressValue(getLIRKind(), newBase, newOffset, immediate, scaled, addressingMode);
+        }
+        return this;
+    }
+
+    @Override
+    protected void visitEachComponent(LIRInstruction inst, LIRInstruction.OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, offset, mode, flags);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,49 @@
+/*
+ * 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.lir.aarch64;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.gen.ArithmeticLIRGeneratorTool;
+
+/**
+ * This interface can be used to generate AArch64 LIR for arithmetic operations.
+ */
+public interface AArch64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorTool {
+
+    Value emitMathLog(Value input, boolean base10);
+
+    Value emitMathCos(Value input);
+
+    Value emitMathSin(Value input);
+
+    Value emitMathTan(Value input);
+
+    Value emitCountLeadingZeros(Value value);
+
+    Value emitCountTrailingZeros(Value value);
+
+    void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64ArithmeticOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,414 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.ARITHMETIC;
+import static com.oracle.graal.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.LOGICAL;
+import static com.oracle.graal.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.NONE;
+import static com.oracle.graal.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.SHIFT;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64Assembler.ConditionFlag;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public enum AArch64ArithmeticOp {
+    // TODO At least add and sub *can* be used with SP, so this should be supported
+    NEG,
+    NOT,
+    ADD(ARITHMETIC),
+    ADDS(ARITHMETIC),
+    SUB(ARITHMETIC),
+    SUBS(ARITHMETIC),
+    MUL,
+    DIV,
+    SMULH,
+    UMULH,
+    REM,
+    UDIV,
+    UREM,
+    AND(LOGICAL),
+    ANDS(LOGICAL),
+    OR(LOGICAL),
+    XOR(LOGICAL),
+    SHL(SHIFT),
+    LSHR(SHIFT),
+    ASHR(SHIFT),
+    ABS,
+
+    FADD,
+    FSUB,
+    FMUL,
+    FDIV,
+    FREM,
+    FNEG,
+    FABS,
+    SQRT;
+
+    /**
+     * Specifies what constants can be used directly without having to be loaded into a register
+     * with the given instruction.
+     */
+    public enum ARMv8ConstantCategory {
+        NONE,
+        LOGICAL,
+        ARITHMETIC,
+        SHIFT
+    }
+
+    public final ARMv8ConstantCategory category;
+
+    AArch64ArithmeticOp(ARMv8ConstantCategory category) {
+        this.category = category;
+    }
+
+    AArch64ArithmeticOp() {
+        this(NONE);
+    }
+
+    public static class UnaryOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<UnaryOp> TYPE = LIRInstructionClass.create(UnaryOp.class);
+
+        @Opcode private final AArch64ArithmeticOp opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+
+        public UnaryOp(AArch64ArithmeticOp opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src = asRegister(x);
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (opcode) {
+                case NEG:
+                    masm.sub(size, dst, zr, src);
+                    break;
+                case FNEG:
+                    masm.fneg(size, dst, src);
+                    break;
+                case NOT:
+                    masm.not(size, dst, src);
+                    break;
+                case ABS:
+                    masm.cmp(size, src, 0);
+                    masm.csneg(size, dst, src, ConditionFlag.LT);
+                    break;
+                case FABS:
+                    masm.fabs(size, dst, src);
+                    break;
+                case SQRT:
+                    masm.fsqrt(size, dst, src);
+                    break;
+                default:
+                    throw JVMCIError.shouldNotReachHere("op=" + opcode.name());
+            }
+        }
+    }
+
+    public static class BinaryConstOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryConstOp> TYPE = LIRInstructionClass.create(BinaryConstOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue a;
+        private final JavaConstant b;
+
+        public BinaryConstOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, JavaConstant b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            assert op.category != NONE;
+            Register dst = asRegister(result);
+            Register src = asRegister(a);
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    // Don't use asInt() here, since we can't use asInt on a long variable, even
+                    // if the constant easily fits as an int.
+                    assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong());
+                    masm.add(size, dst, src, (int) b.asLong());
+                    break;
+                case SUB:
+                    // Don't use asInt() here, since we can't use asInt on a long variable, even
+                    // if the constant easily fits as an int.
+                    assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong());
+                    masm.sub(size, dst, src, (int) b.asLong());
+                    break;
+                case AND:
+                    masm.and(size, dst, src, b.asLong());
+                    break;
+                case ANDS:
+                    masm.ands(size, dst, src, b.asLong());
+                    break;
+                case OR:
+                    masm.or(size, dst, src, b.asLong());
+                    break;
+                case XOR:
+                    masm.eor(size, dst, src, b.asLong());
+                    break;
+                case SHL:
+                    masm.shl(size, dst, src, b.asLong());
+                    break;
+                case LSHR:
+                    masm.lshr(size, dst, src, b.asLong());
+                    break;
+                case ASHR:
+                    masm.ashr(size, dst, src, b.asLong());
+                    break;
+                default:
+                    throw JVMCIError.shouldNotReachHere("op=" + op.name());
+            }
+        }
+    }
+
+    public static class BinaryOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryConstOp> TYPE = LIRInstructionClass.create(BinaryConstOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue a;
+        @Use({REG}) protected AllocatableValue b;
+
+        public BinaryOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src1 = asRegister(a);
+            Register src2 = asRegister(b);
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    masm.add(size, dst, src1, src2);
+                    break;
+                case ADDS:
+                    masm.adds(size, dst, src1, src2);
+                    break;
+                case SUB:
+                    masm.sub(size, dst, src1, src2);
+                    break;
+                case SUBS:
+                    masm.subs(size, dst, src1, src2);
+                    break;
+                case MUL:
+                    masm.mul(size, dst, src1, src2);
+                    break;
+                case UMULH:
+                    masm.umulh(size, dst, src1, src2);
+                    break;
+                case SMULH:
+                    masm.smulh(size, dst, src1, src2);
+                    break;
+                case DIV:
+                    masm.sdiv(size, dst, src1, src2);
+                    break;
+                case UDIV:
+                    masm.udiv(size, dst, src1, src2);
+                    break;
+                case AND:
+                    masm.and(size, dst, src1, src2);
+                    break;
+                case ANDS:
+                    masm.ands(size, dst, src1, src2);
+                    break;
+                case OR:
+                    masm.or(size, dst, src1, src2);
+                    break;
+                case XOR:
+                    masm.eor(size, dst, src1, src2);
+                    break;
+                case SHL:
+                    masm.shl(size, dst, src1, src2);
+                    break;
+                case LSHR:
+                    masm.lshr(size, dst, src1, src2);
+                    break;
+                case ASHR:
+                    masm.ashr(size, dst, src1, src2);
+                    break;
+                case FADD:
+                    masm.fadd(size, dst, src1, src2);
+                    break;
+                case FSUB:
+                    masm.fsub(size, dst, src1, src2);
+                    break;
+                case FMUL:
+                    masm.fmul(size, dst, src1, src2);
+                    break;
+                case FDIV:
+                    masm.fdiv(size, dst, src1, src2);
+                    break;
+                default:
+                    throw JVMCIError.shouldNotReachHere("op=" + op.name());
+            }
+        }
+    }
+
+    /**
+     * Class used for instructions that have to reuse one of their arguments. This only applies to
+     * the remainder instructions at the moment, since we have to compute n % d using rem = n -
+     * TruncatingDivision(n, d) * d
+     *
+     * TODO (das) Replace the remainder nodes in the LIR.
+     */
+    public static class BinaryCompositeOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<BinaryCompositeOp> TYPE = LIRInstructionClass.create(BinaryCompositeOp.class);
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def({REG}) protected AllocatableValue result;
+        @Alive({REG}) protected AllocatableValue a;
+        @Alive({REG}) protected AllocatableValue b;
+
+        public BinaryCompositeOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) {
+            super(TYPE);
+            this.op = op;
+            this.result = result;
+            this.a = a;
+            this.b = b;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            Register src1 = asRegister(a);
+            Register src2 = asRegister(b);
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case REM:
+                    masm.rem(size, dst, src1, src2);
+                    break;
+                case UREM:
+                    masm.urem(size, dst, src1, src2);
+                    break;
+                case FREM:
+                    masm.frem(size, dst, src1, src2);
+                    break;
+                default:
+                    throw JVMCIError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static class AddSubShiftOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<AddSubShiftOp> TYPE = LIRInstructionClass.create(AddSubShiftOp.class);
+
+        @Opcode private final AArch64ArithmeticOp op;
+        @Def(REG) protected AllocatableValue result;
+        @Use(REG) protected AllocatableValue src1;
+        @Use(REG) protected AllocatableValue src2;
+        private final AArch64MacroAssembler.ShiftType shiftType;
+        private final int shiftAmt;
+
+        /**
+         * Computes <code>result = src1 <op> src2 <shiftType> <shiftAmt></code>.
+         */
+        public AddSubShiftOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64MacroAssembler.ShiftType shiftType, int shiftAmt) {
+            super(TYPE);
+            assert op == ADD || op == SUB;
+            this.op = op;
+            this.result = result;
+            this.src1 = src1;
+            this.src2 = src2;
+            this.shiftType = shiftType;
+            this.shiftAmt = shiftAmt;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            switch (op) {
+                case ADD:
+                    masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt);
+                    break;
+                case SUB:
+                    masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt);
+                    break;
+                default:
+                    throw JVMCIError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static class ExtendedAddShiftOp extends AArch64LIRInstruction {
+        private static final LIRInstructionClass<ExtendedAddShiftOp> TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class);
+        @Def(REG) protected AllocatableValue result;
+        @Use(REG) protected AllocatableValue src1;
+        @Use(REG) protected AllocatableValue src2;
+        private final AArch64Assembler.ExtendType extendType;
+        private final int shiftAmt;
+
+        /**
+         * Computes <code>result = src1 + extendType(src2) << shiftAmt</code>.
+         *
+         * @param extendType defines how src2 is extended to the same size as src1.
+         * @param shiftAmt must be in range 0 to 4.
+         */
+        public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) {
+            super(TYPE);
+            this.result = result;
+            this.src1 = src1;
+            this.src2 = src2;
+            this.extendType = extendType;
+            this.shiftAmt = shiftAmt;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // TODO remove
+            int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64BitManipulationOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,89 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+/**
+ * Bit manipulation ops for ARMv8 ISA.
+ */
+public class AArch64BitManipulationOp extends AArch64LIRInstruction {
+    public enum BitManipulationOpCode {
+        BSF,
+        BSR,
+        BSWP,
+        CLZ,
+    }
+
+    private static final LIRInstructionClass<AArch64BitManipulationOp> TYPE = LIRInstructionClass.create(AArch64BitManipulationOp.class);
+
+    @Opcode private final BitManipulationOpCode opcode;
+    @Def protected AllocatableValue result;
+    @Use({REG}) protected AllocatableValue input;
+
+    public AArch64BitManipulationOp(BitManipulationOpCode opcode, AllocatableValue result, AllocatableValue input) {
+        super(TYPE);
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register dst = asRegister(result);
+        Register src = asRegister(input);
+        // TODO remove
+        int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        switch (opcode) {
+            case CLZ:
+                masm.clz(size, dst, src);
+                break;
+            case BSR:
+                // BSR == <type width> - 1 - CLZ(input)
+                masm.clz(size, dst, src);
+                masm.neg(size, dst, dst);
+                masm.add(size, dst, dst, size - 1);
+                break;
+            case BSF:
+                // BSF == CLZ(rev(input))
+                masm.rev(size, dst, src);
+                masm.clz(size, dst, dst);
+                break;
+            case BSWP:
+                masm.rev(size, dst, src);
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64BlockEndOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,45 @@
+/*
+ * 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.lir.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public abstract class AArch64BlockEndOp extends StandardOp.AbstractBlockEndOp {
+
+    public static final LIRInstructionClass<AArch64BlockEndOp> TYPE = LIRInstructionClass.create(AArch64BlockEndOp.class);
+
+    protected AArch64BlockEndOp(LIRInstructionClass<? extends StandardOp.AbstractBlockEndOp> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AArch64MacroAssembler) crb.asm);
+    }
+
+    public abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64BreakpointOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,53 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.AArch64ExceptionCode;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+@Opcode("BREAKPOINT")
+public class AArch64BreakpointOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64BreakpointOp> TYPE = LIRInstructionClass.create(AArch64BreakpointOp.class);
+
+    /**
+     * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger).
+     */
+    @Use({REG, STACK}) private Value[] parameters;
+
+    public AArch64BreakpointOp(Value[] parameters) {
+        super(TYPE);
+        this.parameters = parameters;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        masm.brk(AArch64ExceptionCode.BREAKPOINT);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64Call.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,242 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.InvokeTarget;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public class AArch64Call {
+
+    public abstract static class CallOp extends AArch64LIRInstruction {
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @Temp protected Value[] temps;
+        @State protected LIRFrameState state;
+
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c);
+            this.result = result;
+            this.parameters = parameters;
+            this.state = state;
+            this.temps = temps;
+            assert temps != null;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return true;
+        }
+    }
+
+    public abstract static class MethodCallOp extends CallOp {
+        protected final ResolvedJavaMethod callTarget;
+
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+    }
+
+    @Opcode("CALL_INDIRECT")
+    public static class IndirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
+
+        @Use({REG}) protected Value targetAddress;
+
+        public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
+            this(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        }
+
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
+                        LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
+            this.targetAddress = targetAddress;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register target = asRegister(targetAddress);
+            indirectCall(crb, masm, target, callTarget, state);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, " + "it must be in a fixed register for now";
+        }
+    }
+
+    @Opcode("CALL_DIRECT")
+    public abstract static class DirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
+
+        public DirectCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, target, 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);
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, state);
+        }
+    }
+
+    public abstract static class ForeignCallOp extends CallOp {
+        protected final ForeignCallLinkage callTarget;
+
+        protected ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
+            this.callTarget = callTarget;
+        }
+
+        @Override
+        public boolean destroysCallerSavedRegisters() {
+            return callTarget.destroysRegisters();
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitCall(crb, masm);
+        }
+
+        protected abstract void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+    }
+
+    @Opcode("NEAR_FOREIGN_CALL")
+    public static class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
+
+        public DirectNearForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            directCall(crb, masm, callTarget, null, state);
+        }
+    }
+
+    @Opcode("FAR_FOREIGN_CALL")
+    public static class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
+
+        public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(TYPE, callTarget, result, parameters, temps, state);
+        }
+
+        @Override
+        protected void emitCall(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // We can use any scratch register we want, since we know that they have been saved
+            // before calling.
+            directCall(crb, masm, callTarget, AArch64.r8, state);
+        }
+    }
+
+    /**
+     * Tests whether linkage can be called directly under all circumstances without the need for a
+     * scratch register.
+     *
+     * Note this is a pessimistic assumption: This may return false despite a near call/jump being
+     * adequate.
+     *
+     * @param linkage Foreign call description
+     * @return true if foreign call can be called directly and does not need a scratch register to
+     *         load the address into.
+     */
+    public static boolean isNearCall(ForeignCallLinkage linkage) {
+        long maxOffset = linkage.getMaxCallTargetOffset();
+        return maxOffset != -1 && AArch64MacroAssembler.isBranchImmediateOffset(maxOffset);
+    }
+
+    public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) {
+        int before = masm.position();
+        if (scratch != null) {
+            // offset might not fit into a 28-bit immediate, generate an indirect call with a 64-bit
+            // immediate
+            // address which is fixed up by HotSpot.
+            masm.forceMov(scratch, 0L);
+            masm.blr(scratch);
+        } else {
+            // address is fixed up by HotSpot.
+            masm.bl(0);
+        }
+        int after = masm.position();
+        crb.recordDirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
+        int before = masm.position();
+        masm.blr(dst);
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, callTarget, info);
+        crb.recordExceptionHandlers(after, info);
+        masm.ensureUniquePC();
+    }
+
+    public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) {
+        int before = masm.position();
+        // Address is fixed up later by c++ code.
+        masm.jmp();
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) {
+        int before = masm.position();
+        masm.jmp(dst);
+        int after = masm.position();
+        crb.recordIndirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+    public static void directConditionalJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target, AArch64Assembler.ConditionFlag cond) {
+        int before = masm.position();
+        masm.branchConditionally(cond);
+        int after = masm.position();
+        crb.recordDirectCall(before, after, target, null);
+        masm.ensureUniquePC();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64Compare.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,151 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public class AArch64Compare {
+
+    public static class CompareOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompareOp> TYPE = LIRInstructionClass.create(CompareOp.class);
+
+        @Use protected AllocatableValue x;
+        @Use({REG, CONST}) protected Value y;
+
+        public CompareOp(AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            assert ((AArch64Kind) x.getPlatformKind()).isInteger() && ((AArch64Kind) y.getPlatformKind()).isInteger();
+            assert x.getPlatformKind() == y.getPlatformKind();
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            gpCompare(masm, x, y);
+        }
+    }
+
+    /**
+     * Compares integer values x and y.
+     *
+     * @param x integer value to compare. May not be null.
+     * @param y integer value to compare. May not be null.
+     */
+    public static void gpCompare(AArch64MacroAssembler masm, AllocatableValue x, Value y) {
+        int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        if (isRegister(y)) {
+            masm.cmp(size, asRegister(x), asRegister(y));
+        } else {
+            JavaConstant c = asJavaConstant(y);
+            assert NumUtil.isInt(c.asLong());
+            masm.cmp(size, asRegister(x), (int) c.asLong());
+        }
+    }
+
+    public static class FloatCompareOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<FloatCompareOp> TYPE = LIRInstructionClass.create(FloatCompareOp.class);
+
+        @Use protected AllocatableValue x;
+        @Use({REG, CONST}) protected Value y;
+        private final Condition condition;
+        private final boolean unorderedIsTrue;
+
+        public FloatCompareOp(AllocatableValue x, AllocatableValue y, Condition condition, boolean unorderedIsTrue) {
+            super(TYPE);
+            assert !isJavaConstant(y) || isFloatCmpConstant(y, condition, unorderedIsTrue);
+            this.x = x;
+            this.y = y;
+            this.condition = condition;
+            this.unorderedIsTrue = unorderedIsTrue;
+        }
+
+        /**
+         * Checks if val can be used as a constant for the gpCompare operation or not.
+         */
+        public static boolean isFloatCmpConstant(Value val, Condition condition, boolean unorderedIsTrue) {
+            // If the condition is "EQ || unordered" or "NE && unordered" we have to use 2 registers
+            // in any case.
+            if (!(condition == Condition.EQ && unorderedIsTrue || condition == Condition.NE && !unorderedIsTrue)) {
+                return false;
+            }
+            return isJavaConstant(val) && asJavaConstant(val).isDefaultForKind();
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            assert isRegister(x);
+            int size = x.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            if (isRegister(y)) {
+                masm.fcmp(size, asRegister(x), asRegister(y));
+                // There is no condition code for "EQ || unordered" nor one for "NE && unordered",
+                // so we have to fix them up ourselves.
+                // In both cases we combine the asked for condition into the EQ, respectively NE
+                // condition, i.e.
+                // if EQ && unoreredIsTrue, then the EQ flag will be set if the two values gpCompare
+                // unequal but are
+                // unordered.
+                if (condition == Condition.EQ && unorderedIsTrue) {
+                    // if f1 ordered f2:
+                    // result = f1 == f2
+                    // else:
+                    // result = EQUAL
+                    int nzcv = 0b0100;   // EQUAL -> Z = 1
+                    masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC);
+                } else if (condition == Condition.NE && !unorderedIsTrue) {
+                    // if f1 ordered f2:
+                    // result = f1 != f2
+                    // else:
+                    // result = !NE == EQUAL
+                    int nzcv = 0b0100;   // EQUAL -> Z = 1
+                    masm.fccmp(size, asRegister(x), asRegister(y), nzcv, AArch64Assembler.ConditionFlag.VC);
+                }
+            } else {
+                // cmp against +0.0
+                masm.fcmpZero(size, asRegister(x));
+            }
+        }
+
+        @Override
+        public void verify() {
+            assert x.getPlatformKind().equals(y.getPlatformKind()) : "a: " + x + " b: " + y;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64ControlFlow.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,303 @@
+/*
+ * 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.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.function.Function;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CompilationResult.JumpTable;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.LIRKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler.PatchLabelKind;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.lir.ConstantValue;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.LabelRef;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.SwitchStrategy;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public class AArch64ControlFlow {
+
+    /**
+     * Compares integer register to 0 and branches if condition is true. Condition may only be equal
+     * or non-equal.
+     */
+    // TODO (das) where do we need this?
+    // public static class CompareAndBranchOp extends AArch64LIRInstruction implements
+    // StandardOp.BranchOp {
+    // private final ConditionFlag condition;
+    // private final LabelRef destination;
+    // @Use({REG}) private Value x;
+    //
+    // public CompareAndBranchOp(Condition condition, LabelRef destination, Value x) {
+    // assert condition == Condition.EQ || condition == Condition.NE;
+    // assert ARMv8.isGpKind(x.getKind());
+    // this.condition = condition == Condition.EQ ? ConditionFlag.EQ : ConditionFlag.NE;
+    // this.destination = destination;
+    // this.x = x;
+    // }
+    //
+    // @Override
+    // public void emitCode(CompilationResultBuilder crb, ARMv8MacroAssembler masm) {
+    // int size = ARMv8.bitsize(x.getKind());
+    // if (condition == ConditionFlag.EQ) {
+    // masm.cbz(size, asRegister(x), destination.label());
+    // } else {
+    // masm.cbnz(size, asRegister(x), destination.label());
+    // }
+    // }
+    // }
+
+    public static class BranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
+
+        private final AArch64Assembler.ConditionFlag condition;
+        private final LabelRef trueDestination;
+        private final LabelRef falseDestination;
+
+        private final double trueDestinationProbability;
+
+        public BranchOp(AArch64Assembler.ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            super(TYPE);
+            this.condition = condition;
+            this.trueDestination = trueDestination;
+            this.falseDestination = falseDestination;
+            this.trueDestinationProbability = trueDestinationProbability;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            /*
+             * Explanation: Depending on what the successor edge is, we can use the fall-through to
+             * optimize the generated code. If neither is a successor edge, use the branch
+             * probability to try to take the conditional jump as often as possible to avoid
+             * executing two instructions instead of one.
+             */
+            if (crb.isSuccessorEdge(trueDestination)) {
+                masm.branchConditionally(condition.negate(), falseDestination.label());
+            } else if (crb.isSuccessorEdge(falseDestination)) {
+                masm.branchConditionally(condition, trueDestination.label());
+            } else if (trueDestinationProbability < 0.5) {
+                masm.branchConditionally(condition.negate(), falseDestination.label());
+                masm.jmp(trueDestination.label());
+            } else {
+                masm.branchConditionally(condition, trueDestination.label());
+                masm.jmp(falseDestination.label());
+            }
+        }
+
+    }
+
+    @Opcode("CMOVE")
+    public static class CondMoveOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
+
+        @Def protected Value result;
+        @Use protected Value trueValue;
+        @Use protected Value falseValue;
+        private final AArch64Assembler.ConditionFlag condition;
+
+        public CondMoveOp(Variable result, AArch64Assembler.ConditionFlag condition, Value trueValue, Value falseValue) {
+            super(TYPE);
+            assert trueValue.getPlatformKind() == falseValue.getPlatformKind() && trueValue.getPlatformKind() == result.getPlatformKind();
+            this.result = result;
+            this.condition = condition;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Kind kind = (AArch64Kind) trueValue.getPlatformKind();
+            int size = kind.getSizeInBytes() * Byte.SIZE;
+            if (kind.isInteger()) {
+                masm.cmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition);
+            } else {
+                masm.fcmov(size, asRegister(result), asRegister(trueValue), asRegister(falseValue), condition);
+            }
+        }
+    }
+
+    public static class StrategySwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
+
+        private final Constant[] keyConstants;
+        private final SwitchStrategy strategy;
+        private final Function<Condition, AArch64Assembler.ConditionFlag> converter;
+        private final LabelRef[] keyTargets;
+        private final LabelRef defaultTarget;
+        @Alive protected Value key;
+        // TODO (das) This could be optimized: We only need the scratch register in case of a
+        // datapatch, or too large
+        // immediates.
+        @Temp protected Value scratch;
+
+        public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, Function<Condition, AArch64Assembler.ConditionFlag> converter) {
+            super(TYPE);
+            this.strategy = strategy;
+            this.converter = converter;
+            this.keyConstants = strategy.getKeyConstants();
+            this.keyTargets = keyTargets;
+            this.defaultTarget = defaultTarget;
+            this.key = key;
+            this.scratch = scratch;
+            assert keyConstants.length == keyTargets.length;
+            assert keyConstants.length == strategy.keyProbabilities.length;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            strategy.run(new SwitchClosure(crb, masm));
+        }
+
+        private class SwitchClosure extends SwitchStrategy.BaseSwitchClosure {
+            private final AArch64MacroAssembler masm;
+            private final CompilationResultBuilder crb;
+
+            public SwitchClosure(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+                super(crb, masm, keyTargets, defaultTarget);
+                this.masm = masm;
+                this.crb = crb;
+            }
+
+            @Override
+            protected void conditionalJump(int index, Condition condition, Label target) {
+                emitComparison(keyConstants[index]);
+                masm.branchConditionally(converter.apply(condition), target);
+            }
+
+            private void emitComparison(Constant c) {
+                JavaConstant jc = (JavaConstant) c;
+                ConstantValue constVal = new ConstantValue(LIRKind.value(key.getPlatformKind()), c);
+                switch (jc.getJavaKind()) {
+                    case Int:
+                        long lc = jc.asLong();
+                        assert NumUtil.isInt(lc);
+                        if (crb.codeCache.needsDataPatch(jc)) {
+                            crb.recordInlineDataInCode(jc);
+                            masm.forceMov(asRegister(scratch), (int) lc);
+                            masm.cmp(32, asRegister(key), asRegister(scratch));
+                        } else {
+                            emitCompare(crb, masm, key, scratch, constVal);
+                        }
+                        break;
+                    case Long:
+                        emitCompare(crb, masm, key, scratch, constVal);
+                        break;
+                    case Object:
+                        emitCompare(crb, masm, key, scratch, constVal);
+                        break;
+                    default:
+                        throw new JVMCIError("switch only supported for int, long and object");
+                }
+            }
+        }
+    }
+
+    public static class TableSwitchOp extends AArch64BlockEndOp implements StandardOp.BlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
+
+        private final int lowKey;
+        private final LabelRef defaultTarget;
+        private final LabelRef[] targets;
+        @Alive protected Variable keyValue;
+        @Temp protected Variable scratchValue;
+
+        public TableSwitchOp(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Variable key, Variable scratch) {
+            super(TYPE);
+            this.lowKey = lowKey;
+            this.defaultTarget = defaultTarget;
+            this.targets = targets;
+            this.keyValue = key;
+            this.scratchValue = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register key = asRegister(keyValue);
+            Register scratch = asRegister(scratchValue);
+            if (lowKey != 0) {
+                if (AArch64MacroAssembler.isArithmeticImmediate(lowKey)) {
+                    masm.sub(32, key, key, lowKey);
+                } else {
+                    ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(lowKey));
+                    AArch64Move.move(crb, masm, scratchValue, constVal);
+                    masm.sub(32, key, key, scratch);
+                }
+            }
+            if (defaultTarget != null) {
+                // if key is not in table range, jump to default target if it exists.
+                ConstantValue constVal = new ConstantValue(LIRKind.value(AArch64Kind.WORD), JavaConstant.forInt(targets.length));
+                emitCompare(crb, masm, keyValue, scratchValue, constVal);
+                masm.branchConditionally(AArch64Assembler.ConditionFlag.HS, defaultTarget.label());
+            }
+
+            // Load the start address of the jump table - which starts 3 instructions after the adr
+            // - into scratch.
+            masm.adr(scratch, 4 * 3);
+            masm.ldr(32, scratch, AArch64Address.createRegisterOffsetAddress(scratch, key, /* scaled */true));
+            masm.jmp(scratch);
+            int jumpTablePos = masm.position();
+            // emit jump table entries
+            for (LabelRef target : targets) {
+                Label label = target.label();
+                if (label.isBound()) {
+                    masm.emitInt(target.label().position());
+                } else {
+                    label.addPatchAt(masm.position());
+                    masm.emitInt(PatchLabelKind.JUMP_ADDRESS.encoding);
+                }
+            }
+            JumpTable jt = new JumpTable(jumpTablePos, lowKey, lowKey + targets.length - 1, 4);
+            crb.compilationResult.addAnnotation(jt);
+        }
+    }
+
+    private static void emitCompare(CompilationResultBuilder crb, AArch64MacroAssembler masm, Value key, Value scratchValue, ConstantValue c) {
+        long imm = c.getJavaConstant().asLong();
+        int size = key.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        if (AArch64MacroAssembler.isComparisonImmediate(imm)) {
+            masm.cmp(size, asRegister(key), (int) imm);
+        } else {
+            AArch64Move.move(crb, masm, asAllocatableValue(scratchValue), c);
+            masm.cmp(size, asRegister(key), asRegister(scratchValue));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64FrameMap.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,117 @@
+/*
+ * 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.lir.aarch64;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.LIRKind;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.lir.framemap.FrameMap;
+
+/**
+ * AArch64 specific frame map.
+ * <p/>
+ * This is the format of an AArch64 stack frame:
+ * <p/>
+ *
+ * <pre>
+ *   Base       Contents
+ *
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *   ---------+--------------------------------+-------------------------
+ *            | return address                 |    |            ^
+ *            | prev. frame pointer            |    |            |
+ *            +--------------------------------+    |            |
+ *            | spill slot 0                   |    | negative   |      ^
+ *    callee  :     ...                        :    v offsets    |      |
+ *    frame   | spill slot n                   |  -----        total  frame
+ *            +--------------------------------+               frame  size
+ *            | alignment padding              |               size     |
+ *            +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |      |
+ *            :     ...                        :    | positive   |      |
+ *            | outgoing overflow argument 0   |    | offsets    v      v
+ *    %sp-->  +--------------------------------+---------------------------
+ *
+ * </pre>
+ *
+ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such
+ * a block may be greater than the size of a normal spill slot or the word size.
+ * <p/>
+ * A runtime can reserve space at the beginning of the overflow argument area. The calling
+ * convention can specify that the first overflow stack argument is not at offset 0, but at a
+ * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that
+ * call-free methods also have this space reserved. Then the VM can use the memory at offset 0
+ * relative to the stack pointer.
+ * <p/>
+ */
+public class AArch64FrameMap extends FrameMap {
+    // Note: Spill size includes callee save area
+
+    /**
+     * Creates a new frame map for the specified method.
+     */
+    public AArch64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) {
+        super(codeCache, registerConfig, referenceMapFactory);
+        initialSpillSize = frameSetupSize();
+        spillSize = initialSpillSize;
+    }
+
+    @Override
+    public int totalFrameSize() {
+        // frameSize + return address + frame pointer
+        return frameSize() + frameSetupSize();
+    }
+
+    private int frameSetupSize() {
+        // Size of return address and frame pointer that are saved in function prologue
+        return getTarget().arch.getWordSize() * 2;
+    }
+
+    @Override
+    public int currentFrameSize() {
+        return alignFrameSize(spillSize + outgoingSize - frameSetupSize());
+    }
+
+    @Override
+    protected int alignFrameSize(int size) {
+        return NumUtil.roundUp(size, getTarget().stackAlignment);
+    }
+
+    @Override
+    protected StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset) {
+        return StackSlot.get(kind, -spillSize + additionalOffset, true);
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        // XXX This is very likely not correct.
+        assert spillSize == initialSpillSize : "Deoptimization rescue slot must be the first stack slot";
+        return allocateSpillSlot(LIRKind.value(AArch64Kind.QWORD));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64FrameMapBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,41 @@
+/*
+ * 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.lir.aarch64;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+
+import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.lir.framemap.FrameMapBuilderImpl;
+
+public class AArch64FrameMapBuilder extends FrameMapBuilderImpl {
+
+    public AArch64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
+        super(frameMap, codeCache, registerConfig);
+    }
+
+    public StackSlot allocateDeoptimizationRescueSlot() {
+        return ((AArch64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64LIRInstruction.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public abstract class AArch64LIRInstruction extends LIRInstruction {
+    protected AArch64LIRInstruction(LIRInstructionClass<? extends AArch64LIRInstruction> c) {
+        super(c);
+    }
+
+    @Override
+    public final void emitCode(CompilationResultBuilder crb) {
+        emitCode(crb, (AArch64MacroAssembler) crb.asm);
+    }
+
+    public abstract void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64Move.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,558 @@
+/*
+ * 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.lir.aarch64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
+import static com.oracle.graal.lir.LIRValueUtil.asJavaConstant;
+import static com.oracle.graal.lir.LIRValueUtil.isJavaConstant;
+import static jdk.vm.ci.aarch64.AArch64.zr;
+import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.meta.Value;
+
+import com.oracle.graal.asm.Label;
+import com.oracle.graal.asm.aarch64.AArch64Address;
+import com.oracle.graal.asm.aarch64.AArch64Assembler;
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.StandardOp;
+import com.oracle.graal.lir.StandardOp.NullCheck;
+import com.oracle.graal.lir.StandardOp.ValueMoveOp;
+import com.oracle.graal.lir.VirtualStackSlot;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public class AArch64Move {
+
+    @Opcode("MOVE")
+    public static class MoveToRegOp extends AArch64LIRInstruction implements ValueMoveOp {
+        public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
+
+        @Def protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue input;
+
+        public MoveToRegOp(AllocatableValue result, AllocatableValue input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            move(crb, masm, getResult(), getInput());
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    /**
+     * If the destination is a StackSlot we cannot have a StackSlot or Constant as the source, hence
+     * we have to special case this particular combination. Note: We allow a register as the
+     * destination too just to give the register allocator more freedom.
+     */
+    @Opcode("MOVE")
+    public static class MoveToStackOp extends AArch64LIRInstruction implements StandardOp.ValueMoveOp {
+        public static final LIRInstructionClass<MoveToStackOp> TYPE = LIRInstructionClass.create(MoveToStackOp.class);
+
+        @Def({STACK, REG}) protected AllocatableValue result;
+        @Use protected AllocatableValue input;
+
+        public MoveToStackOp(AllocatableValue result, AllocatableValue input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            move(crb, masm, getResult(), getInput());
+        }
+
+        @Override
+        public AllocatableValue getInput() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    @Opcode("MOVE")
+    public static class MoveFromConstOp extends AArch64LIRInstruction implements StandardOp.LoadConstantOp {
+        public static final LIRInstructionClass<MoveFromConstOp> TYPE = LIRInstructionClass.create(MoveFromConstOp.class);
+
+        @Def protected AllocatableValue result;
+        private final JavaConstant input;
+
+        public MoveFromConstOp(AllocatableValue result, JavaConstant input) {
+            super(TYPE);
+            this.result = result;
+            this.input = input;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            const2reg(crb, masm, result, input);
+        }
+
+        @Override
+        public Constant getConstant() {
+            return input;
+        }
+
+        @Override
+        public AllocatableValue getResult() {
+            return result;
+        }
+    }
+
+    public static class LoadAddressOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class);
+
+        @Def protected AllocatableValue result;
+        @Use(COMPOSITE) protected AArch64AddressValue address;
+
+        public LoadAddressOp(AllocatableValue result, AArch64AddressValue address) {
+            super(TYPE);
+            this.result = result;
+            this.address = address;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            AArch64Address adr = address.toAddress();
+            masm.loadAddress(dst, adr, address.getPlatformKind().getSizeInBytes());
+        }
+    }
+
+    public static class LoadDataOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<LoadDataOp> TYPE = LIRInstructionClass.create(LoadDataOp.class);
+
+        @Def protected AllocatableValue result;
+        private final byte[] data;
+
+        public LoadDataOp(AllocatableValue result, byte[] data) {
+            super(TYPE);
+            this.result = result;
+            this.data = data;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register dst = asRegister(result);
+            int alignment = 16;
+            masm.loadAddress(dst, (AArch64Address) crb.recordDataReferenceInCode(data, alignment), alignment);
+        }
+    }
+
+    public static class StackLoadAddressOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class);
+
+        @Def protected AllocatableValue result;
+        @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot;
+
+        public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) {
+            super(TYPE);
+            assert slot instanceof VirtualStackSlot || slot instanceof StackSlot;
+            this.result = result;
+            this.slot = slot;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Address address = (AArch64Address) crb.asAddress(slot);
+            PlatformKind kind = AArch64Kind.QWORD;
+            masm.loadAddress(asRegister(result, kind), address, kind.getSizeInBytes());
+        }
+    }
+
+    public static class MembarOp extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
+
+        @SuppressWarnings("unused") private final int barriers;
+
+        public MembarOp(int barriers) {
+            super(TYPE);
+            this.barriers = barriers;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            // As I understand it load acquire/store release have the same semantics as on IA64
+            // and allow us to handle LoadStore, LoadLoad and StoreStore without an explicit
+            // barrier.
+            // But Graal support to figure out if a load/store is volatile is non-existant so for
+            // now
+            // just use
+            // memory barriers everywhere.
+            // if ((barrier & MemoryBarriers.STORE_LOAD) != 0) {
+            masm.dmb(AArch64MacroAssembler.BarrierKind.ANY_ANY);
+            // }
+        }
+    }
+
+    abstract static class MemOp extends AArch64LIRInstruction implements StandardOp.ImplicitNullCheck {
+
+        protected final AArch64Kind kind;
+        @Use({COMPOSITE}) protected AArch64AddressValue addressValue;
+        @State protected LIRFrameState state;
+
+        public MemOp(LIRInstructionClass<? extends MemOp> c, AArch64Kind kind, AArch64AddressValue address, LIRFrameState state) {
+            super(c);
+            this.kind = kind;
+            this.addressValue = address;
+            this.state = state;
+        }
+
+        protected abstract void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm);
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emitMemAccess(crb, masm);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            int immediate = addressValue.getImmediate();
+            if (state == null && value.equals(addressValue.getBase()) && addressValue.getOffset().equals(Value.ILLEGAL) && immediate >= 0 && immediate < implicitNullCheckLimit) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    public static final class LoadOp extends MemOp {
+        public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
+
+        @Def protected AllocatableValue result;
+
+        public LoadOp(AArch64Kind kind, AllocatableValue result, AArch64AddressValue address, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.result = result;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Address address = addressValue.toAddress();
+            Register dst = asRegister(result);
+
+            int destSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+            int srcSize = kind.getSizeInBytes() * Byte.SIZE;
+            if (kind.isInteger()) {
+                // TODO How to load unsigned chars without the necessary information?
+                masm.ldrs(destSize, srcSize, dst, address);
+            } else {
+                assert srcSize == destSize;
+                masm.fldr(srcSize, dst, address);
+            }
+        }
+    }
+
+    public static class StoreOp extends MemOp {
+        public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class);
+        @Use protected AllocatableValue input;
+
+        public StoreOp(AArch64Kind kind, AArch64AddressValue address, AllocatableValue input, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.input = input;
+        }
+
+        @Override
+        protected void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitStore(crb, masm, kind, addressValue.toAddress(), asRegister(input));
+        }
+    }
+
+    public static final class StoreConstantOp extends MemOp {
+        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
+
+        protected final JavaConstant input;
+
+        public StoreConstantOp(AArch64Kind kind, AArch64AddressValue address, JavaConstant input, LIRFrameState state) {
+            super(TYPE, kind, address, state);
+            this.input = input;
+            if (!input.isDefaultForKind()) {
+                throw JVMCIError.shouldNotReachHere("Can only store null constants to memory");
+            }
+        }
+
+        @Override
+        public void emitMemAccess(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            emitStore(crb, masm, kind, addressValue.toAddress(), zr);
+        }
+    }
+
+    public static final class NullCheckOp extends AArch64LIRInstruction implements NullCheck {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
+
+        @Use(COMPOSITE) protected AArch64AddressValue address;
+        @State protected LIRFrameState state;
+
+        public NullCheckOp(AArch64AddressValue address, LIRFrameState state) {
+            super(TYPE);
+            this.address = address;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            crb.recordImplicitException(masm.position(), state);
+            masm.ldr(64, zr, address.toAddress());
+        }
+
+        public Value getCheckedValue() {
+            return address.base;
+        }
+
+        public LIRFrameState getState() {
+            return state;
+        }
+    }
+
+    /**
+     * Compare and swap instruction. Does the following atomically: <code>
+     *  CAS(newVal, expected, address):
+     *    oldVal = *address
+     *    if oldVal == expected:
+     *        *address = newVal
+     *    return oldVal
+     * </code>
+     */
+    @Opcode("CAS")
+    public static class CompareAndSwap extends AArch64LIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwap> TYPE = LIRInstructionClass.create(CompareAndSwap.class);
+
+        @Def protected AllocatableValue resultValue;
+        @Alive protected Value expectedValue;
+        @Alive protected AllocatableValue newValue;
+        @Alive(COMPOSITE) protected AArch64AddressValue addressValue;
+        @Temp protected AllocatableValue scratchValue;
+
+        public CompareAndSwap(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AArch64AddressValue addressValue, AllocatableValue scratch) {
+            super(TYPE);
+            this.resultValue = result;
+            this.expectedValue = expectedValue;
+            this.newValue = newValue;
+            this.addressValue = addressValue;
+            this.scratchValue = scratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Kind kind = (AArch64Kind) expectedValue.getPlatformKind();
+            assert kind.isInteger();
+            int size = kind.getSizeInBytes() * Byte.SIZE;
+
+            AArch64Address address = addressValue.toAddress();
+            Register result = asRegister(resultValue);
+            Register newVal = asRegister(newValue);
+            Register scratch = asRegister(scratchValue);
+            // We could avoid using a scratch register here, by reusing resultValue for the stlxr
+            // success flag
+            // and issue a mov resultValue, expectedValue in case of success before returning.
+            Label retry = new Label();
+            Label fail = new Label();
+            masm.bind(retry);
+            masm.ldaxr(size, result, address);
+            AArch64Compare.gpCompare(masm, resultValue, expectedValue);
+            masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, fail);
+            masm.stlxr(size, scratch, newVal, address);
+            // if scratch == 0 then write successful, else retry.
+            masm.cbnz(32, scratch, retry);
+            masm.bind(fail);
+        }
+    }
+
+    public static void emitStore(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AArch64Kind kind, AArch64Address dst, Register src) {
+        int destSize = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.str(destSize, src, dst);
+        } else {
+            masm.fstr(destSize, src, dst);
+        }
+    }
+
+    public static void move(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, Value input) {
+        if (isRegister(input)) {
+            if (isRegister(result)) {
+                reg2reg(crb, masm, result, asAllocatableValue(input));
+            } else if (isStackSlot(result)) {
+                reg2stack(crb, masm, result, asAllocatableValue(input));
+            } else {
+                throw JVMCIError.shouldNotReachHere();
+            }
+        } else if (isStackSlot(input)) {
+            if (isRegister(result)) {
+                stack2reg(crb, masm, result, asAllocatableValue(input));
+            } else {
+                throw JVMCIError.shouldNotReachHere();
+            }
+        } else if (isJavaConstant(input)) {
+            if (isRegister(result)) {
+                const2reg(crb, masm, result, asJavaConstant(input));
+            } else {
+                throw JVMCIError.shouldNotReachHere();
+            }
+        } else {
+            throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    private static void reg2reg(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        Register dst = asRegister(result);
+        Register src = asRegister(input);
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.mov(size, dst, src);
+        } else {
+            masm.fmov(size, dst, src);
+        }
+    }
+
+    private static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        AArch64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL);
+        Register src = asRegister(input);
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.str(size, src, dest);
+        } else {
+            masm.fstr(size, src, dest);
+        }
+    }
+
+    private static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+        AArch64Address src = loadStackSlotAddress(crb, masm, asStackSlot(input), result);
+        Register dest = asRegister(result);
+        AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
+        int size = kind.getSizeInBytes() * Byte.SIZE;
+        if (kind.isInteger()) {
+            masm.ldr(size, dest, src);
+        } else {
+            masm.fldr(size, dest, src);
+        }
+    }
+
+    private static void const2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, JavaConstant input) {
+        Register dst = asRegister(result);
+        switch (input.getJavaKind().getStackKind()) {
+            case Int:
+                if (crb.codeCache.needsDataPatch(input)) {
+                    crb.recordInlineDataInCode(input);
+                    masm.forceMov(dst, input.asInt());
+                } else {
+                    masm.mov(dst, input.asInt());
+                }
+                break;
+            case Long:
+                if (crb.codeCache.needsDataPatch(input)) {
+                    crb.recordInlineDataInCode(input);
+                    masm.forceMov(dst, input.asLong());
+                } else {
+                    masm.mov(dst, input.asLong());
+                }
+                break;
+            case Float:
+                if (AArch64MacroAssembler.isFloatImmediate(input.asFloat())) {
+                    masm.fmov(32, dst, input.asFloat());
+                } else {
+                    masm.fldr(32, dst, (AArch64Address) crb.asFloatConstRef(input));
+                }
+                break;
+            case Double:
+                if (AArch64MacroAssembler.isDoubleImmediate(input.asDouble())) {
+                    masm.fmov(64, dst, input.asDouble());
+                } else {
+                    masm.fldr(64, dst, (AArch64Address) crb.asDoubleConstRef(input));
+                }
+                break;
+            case Object:
+                if (input.isNull()) {
+                    masm.mov(dst, 0);
+                } else if (crb.target.inlineObjects) {
+                    crb.recordInlineDataInCode(input);
+                    masm.forceMov(dst, 0xDEADDEADDEADDEADL);
+                } else {
+                    masm.ldr(64, dst, (AArch64Address) crb.recordDataReferenceInCode(input, 8));
+                }
+                break;
+            default:
+                throw JVMCIError.shouldNotReachHere("kind=" + input.getJavaKind().getStackKind());
+        }
+    }
+
+    /**
+     * Returns AArch64Address of given StackSlot. We cannot use CompilationResultBuilder.asAddress
+     * since this calls AArch64MacroAssembler.makeAddress with displacements that may be larger than
+     * 9-bit signed, which cannot be handled by that method.
+     *
+     * Instead we create an address ourselves. We use scaled unsigned addressing since we know the
+     * transfersize, which gives us a 15-bit address range (for longs/doubles) respectively a 14-bit
+     * range (for everything else).
+     *
+     * @param scratch Scratch register that can be used to load address. If Value.ILLEGAL this
+     *            instruction fails if we try to access a StackSlot that is too large to be loaded
+     *            directly.
+     * @return AArch64Address of given StackSlot. Uses scratch register if necessary to do so.
+     */
+    private static AArch64Address loadStackSlotAddress(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot slot, AllocatableValue scratch) {
+        AArch64Kind kind = (AArch64Kind) scratch.getPlatformKind();
+        assert kind.isInteger();
+        int displacement = crb.frameMap.offsetForStackSlot(slot);
+        int transferSize = slot.getPlatformKind().getSizeInBytes();
+        Register scratchReg = Value.ILLEGAL.equals(scratch) ? AArch64.zr : asRegister(scratch);
+        return masm.makeAddress(AArch64.sp, displacement, scratchReg, transferSize, /* allowOverwrite */false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64PauseOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,45 @@
+/*
+ * 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.lir.aarch64;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.Opcode;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+/**
+ * Emits a pause.
+ */
+@Opcode("PAUSE")
+public final class AArch64PauseOp extends AArch64LIRInstruction {
+    public static final LIRInstructionClass<AArch64PauseOp> TYPE = LIRInstructionClass.create(AArch64PauseOp.class);
+
+    public AArch64PauseOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        masm.pause();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64ReinterpretOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,62 @@
+/*
+ * 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.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+/**
+ * Instruction that reinterprets some bit pattern as a different type. It is possible to reinterpret
+ * the following: - int <-> float - long <-> double
+ */
+public class AArch64ReinterpretOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64ReinterpretOp> TYPE = LIRInstructionClass.create(AArch64ReinterpretOp.class);
+
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    public AArch64ReinterpretOp(AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        AArch64Kind from = (AArch64Kind) inputValue.getPlatformKind();
+        AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind();
+        assert from.getSizeInBytes() == to.getSizeInBytes() && from.isInteger() ^ to.isInteger();
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        AArch64Kind to = (AArch64Kind) resultValue.getPlatformKind();
+        final int size = to.getSizeInBytes() * Byte.SIZE;
+        masm.fmov(size, result, input);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.aarch64/src/com/oracle/graal/lir/aarch64/AArch64SignExtendOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,54 @@
+/*
+ * 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.lir.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import com.oracle.graal.asm.aarch64.AArch64MacroAssembler;
+import com.oracle.graal.lir.LIRInstructionClass;
+import com.oracle.graal.lir.asm.CompilationResultBuilder;
+
+public class AArch64SignExtendOp extends AArch64LIRInstruction {
+    private static final LIRInstructionClass<AArch64SignExtendOp> TYPE = LIRInstructionClass.create(AArch64SignExtendOp.class);
+
+    @Def protected AllocatableValue resultValue;
+    @Use protected AllocatableValue inputValue;
+
+    public AArch64SignExtendOp(AllocatableValue resultValue, AllocatableValue inputValue) {
+        super(TYPE);
+        this.resultValue = resultValue;
+        this.inputValue = inputValue;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register input = asRegister(inputValue);
+        int to = resultValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        int from = inputValue.getPlatformKind().getSizeInBytes() * Byte.SIZE;
+        masm.sxt(to, from, result, input);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Tue Jan 05 16:42:05 2016 -0800
@@ -199,7 +199,7 @@
                         masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(jc));
                         break;
                     case Object:
-                        AMD64Move.const2reg(crb, masm, scratch, jc);
+                        AMD64Move.const2reg(crb, masm, asRegister(scratch), jc);
                         masm.cmpptr(keyRegister, asRegister(scratch));
                         break;
                     default:
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Tue Jan 05 16:42:05 2016 -0800
@@ -141,7 +141,7 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             if (isRegister(result)) {
-                const2reg(crb, masm, result, input);
+                const2reg(crb, masm, asRegister(result), input);
             } else {
                 assert isStackSlot(result);
                 const2stack(crb, masm, result, input);
@@ -513,7 +513,7 @@
             }
         } else if (isJavaConstant(input)) {
             if (isRegister(result)) {
-                const2reg(crb, masm, result, asJavaConstant(input));
+                const2reg(crb, masm, asRegister(result), asJavaConstant(input));
             } else if (isStackSlot(result)) {
                 const2stack(crb, masm, result, asJavaConstant(input));
             } else {
@@ -548,7 +548,7 @@
         }
     }
 
-    private static void reg2stack(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Register input) {
+    public static void reg2stack(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, Register input) {
         AMD64Address dest = (AMD64Address) crb.asAddress(result);
         switch (kind) {
             case BYTE:
@@ -574,7 +574,7 @@
         }
     }
 
-    private static void stack2reg(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Value input) {
+    public static void stack2reg(AMD64Kind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Value input) {
         AMD64Address src = (AMD64Address) crb.asAddress(input);
         switch (kind) {
             case BYTE:
@@ -600,7 +600,7 @@
         }
     }
 
-    public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value result, JavaConstant input) {
+    public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, JavaConstant input) {
         /*
          * Note: we use the kind of the input operand (and not the kind of the result operand)
          * because they don't match in all cases. For example, an object constant can be loaded to a
@@ -615,7 +615,7 @@
                 // Do not optimize with an XOR as this instruction may be between
                 // a CMP and a Jcc in which case the XOR will modify the condition
                 // flags and interfere with the Jcc.
-                masm.movl(asRegister(result), input.asInt());
+                masm.movl(result, input.asInt());
 
                 break;
             case Long:
@@ -628,16 +628,16 @@
                 // a CMP and a Jcc in which case the XOR will modify the condition
                 // flags and interfere with the Jcc.
                 if (patch) {
-                    masm.movq(asRegister(result), input.asLong());
+                    masm.movq(result, input.asLong());
                 } else {
                     if (input.asLong() == (int) input.asLong()) {
                         // Sign extended to long
-                        masm.movslq(asRegister(result), (int) input.asLong());
+                        masm.movslq(result, (int) input.asLong());
                     } else if ((input.asLong() & 0xFFFFFFFFL) == input.asLong()) {
                         // Zero extended to long
-                        masm.movl(asRegister(result), (int) input.asLong());
+                        masm.movl(result, (int) input.asLong());
                     } else {
-                        masm.movq(asRegister(result), input.asLong());
+                        masm.movq(result, input.asLong());
                     }
                 }
                 break;
@@ -645,18 +645,18 @@
                 // This is *not* the same as 'constant == 0.0f' in the case where constant is -0.0f
                 if (Float.floatToRawIntBits(input.asFloat()) == Float.floatToRawIntBits(0.0f)) {
                     assert !crb.codeCache.needsDataPatch(input);
-                    masm.xorps(asRegister(result, AMD64Kind.SINGLE), asRegister(result));
+                    masm.xorps(result, result);
                 } else {
-                    masm.movflt(asRegister(result, AMD64Kind.SINGLE), (AMD64Address) crb.asFloatConstRef(input));
+                    masm.movflt(result, (AMD64Address) crb.asFloatConstRef(input));
                 }
                 break;
             case Double:
                 // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d
                 if (Double.doubleToRawLongBits(input.asDouble()) == Double.doubleToRawLongBits(0.0d)) {
                     assert !crb.codeCache.needsDataPatch(input);
-                    masm.xorpd(asRegister(result, AMD64Kind.DOUBLE), asRegister(result));
+                    masm.xorpd(result, result);
                 } else {
-                    masm.movdbl(asRegister(result, AMD64Kind.DOUBLE), (AMD64Address) crb.asDoubleConstRef(input));
+                    masm.movdbl(result, (AMD64Address) crb.asDoubleConstRef(input));
                 }
                 break;
             case Object:
@@ -664,12 +664,12 @@
                 // a CMP and a Jcc in which case the XOR will modify the condition
                 // flags and interfere with the Jcc.
                 if (input.isNull()) {
-                    masm.movq(asRegister(result), 0x0L);
+                    masm.movq(result, 0x0L);
                 } else if (crb.target.inlineObjects) {
                     crb.recordInlineDataInCode(input);
-                    masm.movq(asRegister(result), 0xDEADDEADDEADDEADL);
+                    masm.movq(result, 0xDEADDEADDEADDEADL);
                 } else {
-                    masm.movq(asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(input, 0));
+                    masm.movq(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0));
                 }
                 break;
             default:
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,8 +28,8 @@
 
 import java.util.Arrays;
 
+import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Register;
-import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.meta.AllocatableValue;
 
@@ -71,9 +71,8 @@
         return save.savedRegisters;
     }
 
-    protected void restoreRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, StackSlot input) {
-        RegisterValue result = register.asValue(input.getLIRKind());
-        AMD64Move.move(crb, masm, result, input);
+    protected void restoreRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, StackSlot input) {
+        AMD64Move.stack2reg((AMD64Kind) input.getPlatformKind(), crb, masm, result, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,9 +29,9 @@
 import java.util.Arrays;
 import java.util.Set;
 
+import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterSaveLayout;
-import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.meta.AllocatableValue;
 
@@ -84,9 +84,8 @@
         this.supportsRemove = supportsRemove;
     }
 
-    protected void saveRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, StackSlot result, Register register) {
-        RegisterValue input = register.asValue(result.getLIRKind());
-        AMD64Move.move(crb, masm, result, input);
+    protected void saveRegister(CompilationResultBuilder crb, AMD64MacroAssembler masm, StackSlot result, Register input) {
+        AMD64Move.reg2stack((AMD64Kind) result.getPlatformKind(), crb, masm, result, input);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,10 +28,7 @@
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterSaveLayout;
-import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.LIRKind;
-import jdk.vm.ci.meta.PlatformKind;
 
 import com.oracle.graal.asm.amd64.AMD64MacroAssembler;
 import com.oracle.graal.lir.LIRInstructionClass;
@@ -68,9 +65,7 @@
         for (int i = 0; i < zappedRegisters.length; i++) {
             Register reg = zappedRegisters[i];
             if (reg != null) {
-                PlatformKind kind = crb.target.arch.getLargestStorableKind(reg.getRegisterCategory());
-                RegisterValue registerValue = reg.asValue(LIRKind.value(kind));
-                AMD64Move.const2reg(crb, masm, registerValue, zapValues[i]);
+                AMD64Move.const2reg(crb, masm, reg, zapValues[i]);
             }
         }
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/phases/StackMoveOptimizationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,9 +32,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -46,6 +43,9 @@
 import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
 
 /**
  * Replaces sequential {@link AMD64StackMove}s of the same type with a single
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Jan 05 16:42:05 2016 -0800
@@ -45,10 +45,6 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.LIRKind;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
@@ -68,6 +64,10 @@
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * An implementation of the linear scan register allocator algorithm described in <a
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,10 +32,6 @@
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -49,6 +45,10 @@
 import com.oracle.graal.lir.alloc.lsra.LinearScan.IntervalPredicate;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.AllocationPhase;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 public class LinearScanEliminateSpillMovePhase extends AllocationPhase {
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,9 +27,6 @@
 import static jdk.vm.ci.code.ValueUtil.isRegister;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -39,6 +36,9 @@
 import com.oracle.graal.lir.alloc.lsra.Interval.RegisterBindingLists;
 import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority;
 import com.oracle.graal.lir.alloc.lsra.Interval.State;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 public class OptimizingLinearScanWalker extends LinearScanWalker {
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,9 +25,6 @@
 import java.util.List;
 
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.alloc.TraceBuilder;
@@ -49,6 +46,9 @@
 import com.oracle.graal.lir.phases.AllocationPhase;
 import com.oracle.graal.lir.ssi.SSIUtil;
 import com.oracle.graal.lir.ssi.SSIVerifier;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * An implementation of a Trace Register Allocator as described in <a
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScan.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/lsra/TraceLinearScan.java	Tue Jan 05 16:42:05 2016 -0800
@@ -45,10 +45,6 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.LIRKind;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult;
@@ -71,6 +67,10 @@
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool.MoveFactory;
 import com.oracle.graal.lir.phases.LIRPhase;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * An implementation of the linear scan register allocator algorithm described in <a
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -50,9 +50,6 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.VMConstant;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.asm.AbstractAddress;
 import com.oracle.graal.asm.Assembler;
@@ -65,6 +62,9 @@
 import com.oracle.graal.lir.LIRInstruction;
 import com.oracle.graal.lir.LabelRef;
 import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Fills in a {@link CompilationResult} as its code is being assembled.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Jan 05 16:42:05 2016 -0800
@@ -37,9 +37,6 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.LIRKind;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.compiler.common.cfg.BlockMap;
@@ -61,6 +58,9 @@
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
 
 /**
  * This optimization tries to improve the handling of constants by replacing a single definition of
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -50,9 +50,6 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PlatformKind;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.asm.Label;
 import com.oracle.graal.compiler.common.calc.Condition;
@@ -74,6 +71,9 @@
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.SwitchStrategy;
 import com.oracle.graal.lir.Variable;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -26,9 +26,6 @@
 import java.util.regex.Pattern;
 
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -38,6 +35,9 @@
 import com.oracle.graal.debug.DebugTimer;
 import com.oracle.graal.lir.LIR;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 /**
  * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationStage.java	Tue Jan 05 16:42:05 2016 -0800
@@ -23,10 +23,6 @@
 package com.oracle.graal.lir.phases;
 
 import static com.oracle.graal.lir.phases.LIRPhase.Options.LIROptimization;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.lir.ControlFlowOptimizer;
 import com.oracle.graal.lir.EdgeMoveOptimizer;
@@ -34,6 +30,10 @@
 import com.oracle.graal.lir.RedundantMoveElimination;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
 import com.oracle.graal.lir.profiling.MoveProfiling;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 public class PostAllocationOptimizationStage extends LIRPhaseSuite<PostAllocationOptimizationContext> {
     public static class Options {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -40,9 +40,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.LIRKind;
 import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.options.NestedBooleanOptionValue;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
 
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
 import com.oracle.graal.debug.Debug;
@@ -61,6 +58,9 @@
 import com.oracle.graal.lir.framemap.VirtualStackSlotRange;
 import com.oracle.graal.lir.gen.LIRGenerationResult;
 import com.oracle.graal.lir.phases.AllocationPhase;
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
 
 /**
  * Linear Scan {@link StackSlotAllocator}.
--- a/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopTransformations.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopTransformations.java	Tue Jan 05 16:42:05 2016 -0800
@@ -65,7 +65,6 @@
             Mark mark = graph.getMark();
             peel(loop);
             canonicalizer.applyIncremental(graph, context, mark);
-            loopBegin.removeDeadPhis();
             loop.invalidateFragments();
             if (graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
                 throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DefaultLoopPolicies.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DefaultLoopPolicies.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -28,15 +28,14 @@
 
 import java.util.List;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import jdk.vm.ci.code.BytecodeFrame;
 
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.ControlSplitNode;
+import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.LoopBeginNode;
 import com.oracle.graal.nodes.MergeNode;
 import com.oracle.graal.nodes.VirtualState;
@@ -44,6 +43,9 @@
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.nodes.debug.ControlFlowAnchorNode;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 public class DefaultLoopPolicies implements LoopPolicies {
     @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(500);
@@ -68,6 +70,12 @@
                 if (node instanceof ControlFlowAnchorNode) {
                     return false;
                 }
+                if (node instanceof FrameState) {
+                    FrameState frameState = (FrameState) node;
+                    if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || frameState.bci == BytecodeFrame.UNWIND_BCI) {
+                        return false;
+                    }
+                }
             }
             return true;
         } else {
@@ -91,6 +99,12 @@
                 if (node instanceof ControlFlowAnchorNode) {
                     return false;
                 }
+                if (node instanceof FrameState) {
+                    FrameState frameState = (FrameState) node;
+                    if (frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || frameState.bci == BytecodeFrame.UNWIND_BCI) {
+                        return false;
+                    }
+                }
             }
             return true;
         } else {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -234,7 +234,8 @@
         }
         markStateNodes(loopBegin, usagesToPatch);
 
-        for (PhiNode phi : loopBegin.phis().snapshot()) {
+        List<PhiNode> oldPhis = loopBegin.phis().snapshot();
+        for (PhiNode phi : oldPhis) {
             if (phi.hasNoUsages()) {
                 continue;
             }
@@ -275,7 +276,32 @@
             }
         }
 
-        for (PhiNode deadPhi : loopBegin.phis().filter(n -> n.hasNoUsages()).snapshot()) {
+        int oldPhisSize;
+        do {
+            oldPhisSize = oldPhis.size();
+            int i = 0;
+            outer: while (i < oldPhisSize) {
+                PhiNode oldPhi = oldPhis.get(i);
+                for (Node usage : oldPhi.usages()) {
+                    if (usage instanceof PhiNode && oldPhis.contains(usage)) {
+                        // Do not mark.
+                    } else {
+                        // Mark alive by removing from delete set.
+                        oldPhis.set(i, oldPhis.get(oldPhisSize - 1));
+                        oldPhisSize--;
+                        continue outer;
+                    }
+                }
+                i++;
+            }
+            // Check for progress.
+        } while (oldPhisSize != oldPhis.size());
+
+        for (PhiNode deadPhi : oldPhis) {
+            deadPhi.clearInputs();
+        }
+
+        for (PhiNode deadPhi : oldPhis) {
             if (deadPhi.isAlive()) {
                 GraphUtil.killWithUnusedFloatingInputs(deadPhi);
             }
--- a/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/NodeBenchmark.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.microbenchmarks/src/com/oracle/graal/microbenchmarks/graal/NodeBenchmark.java	Tue Jan 05 16:42:05 2016 -0800
@@ -71,16 +71,6 @@
     public static class HashMapComputeIfAbsent extends NodesState {
     }
 
-    @Benchmark
-    @Warmup(iterations = 20)
-    public void nonNullInputs(HashMapComputeIfAbsent s, Blackhole bh) {
-        for (Node n : s.nodes) {
-            for (Node input : n.inputs().nonNull()) {
-                bh.consume(input);
-            }
-        }
-    }
-
     // Checkstyle: stop method name check
     @Benchmark
     @Warmup(iterations = 20)
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IfNodeCanonicalizationTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IfNodeCanonicalizationTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.directives.GraalDirectives;
 import com.oracle.graal.compiler.test.GraalCompilerTest;
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.nodes.AbstractMergeNode;
 import com.oracle.graal.nodes.IfNode;
 import com.oracle.graal.nodes.LogicNode;
 import com.oracle.graal.nodes.StructuredGraph;
@@ -157,9 +156,7 @@
 
         PhaseContext context = new PhaseContext(getProviders());
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
-            merge.setStateAfter(null);
-        }
+        graph.clearAllStateAfter();
         canonicalizer.apply(graph, context);
 
         new ConvertDeoptimizeToGuardPhase().apply(graph, context);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -78,27 +78,9 @@
     }
 
     public void prepareDelete(FixedNode evacuateFrom) {
-        removeProxies();
         evacuateGuards(evacuateFrom);
     }
 
-    public void removeProxies() {
-        if (this.hasUsages()) {
-            outer: while (true) {
-                for (ProxyNode vpn : proxies().snapshot()) {
-                    ValueNode value = vpn.value();
-                    vpn.replaceAtUsages(value);
-                    vpn.safeDelete();
-                    if (value == this) {
-                        // Guard proxy could have this input as value.
-                        continue outer;
-                    }
-                }
-                break;
-            }
-        }
-    }
-
     @Override
     public boolean verify() {
         assertTrue(predecessor() != null || this == graph().start() || this instanceof AbstractMergeNode, "begin nodes must be connected");
@@ -115,24 +97,7 @@
     }
 
     public NodeIterable<Node> anchored() {
-        return usages().filter(n -> {
-            if (n instanceof ProxyNode) {
-                ProxyNode proxyNode = (ProxyNode) n;
-                return proxyNode.proxyPoint() != this;
-            }
-            return true;
-        });
-    }
-
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    public NodeIterable<ProxyNode> proxies() {
-        return (NodeIterable) usages().filter(n -> {
-            if (n instanceof ProxyNode) {
-                ProxyNode proxyNode = (ProxyNode) n;
-                return proxyNode.proxyPoint() == this;
-            }
-            return false;
-        });
+        return usages();
     }
 
     public NodeIterable<FixedNode> getBlockNodes() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMergeNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMergeNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
-
 import java.util.List;
 
 import com.oracle.graal.debug.Debug;
@@ -105,7 +103,7 @@
             }
             ValueNode removedValue = phi.valueAt(predIndex);
             phi.removeInput(predIndex);
-            if (removedValue != null && removedValue.isAlive() && removedValue.hasNoUsages() && GraphUtil.isFloatingNode().apply(removedValue)) {
+            if (removedValue != null && removedValue.isAlive() && removedValue.hasNoUsages() && GraphUtil.isFloatingNode(removedValue)) {
                 GraphUtil.killWithUnusedFloatingInputs(removedValue);
             }
         }
@@ -171,8 +169,10 @@
                 return;
             }
             for (PhiNode phi : phis()) {
-                if (phi.usages().filter(isNotA(VirtualState.class)).and(node -> !merge.isPhiAtMerge(node)).isNotEmpty()) {
-                    return;
+                for (Node usage : phi.usages()) {
+                    if (!(usage instanceof VirtualState) && !merge.isPhiAtMerge(usage)) {
+                        return;
+                    }
                 }
             }
             Debug.log("Split %s into ends for %s.", this, merge);
@@ -216,8 +216,8 @@
             }
             List<PhiNode> phis = phis().snapshot();
             for (PhiNode phi : phis) {
-                for (Node usage : phi.usages().filter(isNotA(FrameState.class))) {
-                    if (usage != returnNode) {
+                for (Node usage : phi.usages()) {
+                    if (usage != returnNode && !(usage instanceof FrameState)) {
                         return;
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -94,7 +94,7 @@
      */
     public void replace(StructuredGraph graph, Node replacement) {
         assert graph == graph();
-        graph().replaceFloating(this, replacement);
+        replaceAtUsagesAndDelete(replacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Tue Jan 05 16:42:05 2016 -0800
@@ -547,6 +547,12 @@
                 assertTrue(state != null, "must be non-null");
             }
         }
+        if (monitorIds() != null && monitorIds().size() > 0) {
+            int depth = outerLockDepth();
+            for (MonitorIdNode monitor : monitorIds()) {
+                assertTrue(monitor.getLockDepth() == depth++, "wrong depth");
+            }
+        }
         assertTrue(locksSize() == monitorIdCount(), "mismatch in number of locks");
         for (ValueNode value : values) {
             assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes");
@@ -555,6 +561,16 @@
         return super.verify();
     }
 
+    private int outerLockDepth() {
+        int depth = 0;
+        FrameState outer = outerFrameState;
+        while (outer != null) {
+            depth += outer.monitorIdCount();
+            outer = outer.outerFrameState;
+        }
+        return depth;
+    }
+
     @Override
     public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) {
         for (ValueNode value : values) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -488,8 +488,7 @@
             LoopExplosionState queryState = new LoopExplosionState(frameState, null);
             LoopExplosionState existingState = loopScope.iterationStates.get(queryState);
             if (existingState != null) {
-                loopBegin.replaceAtUsages(existingState.merge);
-                loopBegin.safeDelete();
+                loopBegin.replaceAtUsagesAndDelete(existingState.merge);
                 successor.safeDelete();
                 for (EndNode predecessor : predecessors) {
                     existingState.merge.addForwardEnd(predecessor);
@@ -499,8 +498,7 @@
         }
 
         MergeNode merge = methodScope.graph.add(new MergeNode());
-        loopBegin.replaceAtUsages(merge);
-        loopBegin.safeDelete();
+        loopBegin.replaceAtUsagesAndDelete(merge);
         merge.setStateAfter(frameState);
         merge.setNext(successor);
         for (EndNode predecessor : predecessors) {
@@ -653,7 +651,7 @@
                 replacement = phi;
             }
 
-            methodScope.graph.replaceFloating(proxy, replacement);
+            proxy.replaceAtUsagesAndDelete(replacement);
         }
 
         if (merge != null && (merge.stateAfter() == null || phiCreated)) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -275,8 +275,7 @@
                                 if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
                                     Node newNode = graph().findDuplicate(usage);
                                     if (newNode != null) {
-                                        usage.replaceAtUsages(newNode);
-                                        usage.safeDelete();
+                                        usage.replaceAtUsagesAndDelete(newNode);
                                     }
                                 }
                                 if (usage.isAlive()) {
@@ -848,8 +847,9 @@
     }
 
     private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
-        if (falseMerge != null) {
-            for (ProxyNode proxy : successor.proxies().snapshot()) {
+        if (successor instanceof LoopExitNode && falseMerge != null) {
+            LoopExitNode loopExitNode = (LoopExitNode) successor;
+            for (ProxyNode proxy : loopExitNode.proxies().snapshot()) {
                 proxy.replaceFirstInput(successor, falseMerge);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,14 +24,11 @@
 
 import static com.oracle.graal.graph.iterators.NodePredicates.isNotA;
 
-import java.util.Set;
-
 import com.oracle.graal.compiler.common.type.IntegerStamp;
 import com.oracle.graal.graph.IterableNodeType;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.graph.iterators.NodePredicate;
 import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.InputType;
 import com.oracle.graal.nodeinfo.NodeInfo;
@@ -220,7 +217,6 @@
 
     @Override
     public void simplify(SimplifierTool tool) {
-        removeDeadPhis();
         canonicalizePhis(tool);
     }
 
@@ -248,31 +244,6 @@
         this.overflowGuard = overflowGuard;
     }
 
-    /**
-     * Removes dead {@linkplain PhiNode phi nodes} hanging from this node.
-     *
-     * This method uses the heuristic that any node which not a phi node of this LoopBeginNode is
-     * alive. This allows the removal of dead phi loops.
-     */
-    public void removeDeadPhis() {
-        if (phis().isNotEmpty()) {
-            Set<PhiNode> alive = Node.newSet();
-            for (PhiNode phi : phis()) {
-                NodePredicate isAlive = u -> !isPhiAtMerge(u) || alive.contains(u);
-                if (phi.usages().filter(isAlive).isNotEmpty()) {
-                    alive.add(phi);
-                    for (PhiNode keptAlive : phi.values().filter(PhiNode.class).filter(isAlive.negate())) {
-                        alive.add(keptAlive);
-                    }
-                }
-            }
-            for (PhiNode phi : phis().filter(((NodePredicate) alive::contains).negate()).snapshot()) {
-                phi.replaceAtUsages(null);
-                phi.safeDelete();
-            }
-        }
-    }
-
     private static final int NO_INCREMENT = Integer.MIN_VALUE;
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,6 +25,7 @@
 import com.oracle.graal.graph.IterableNodeType;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.iterators.NodeIterable;
 import com.oracle.graal.graph.spi.Simplifiable;
 import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.InputType;
@@ -47,6 +48,50 @@
     }
 
     @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(n -> {
+            if (n instanceof ProxyNode) {
+                ProxyNode proxyNode = (ProxyNode) n;
+                return proxyNode.proxyPoint() != this;
+            }
+            return true;
+        });
+    }
+
+    @Override
+    public void prepareDelete(FixedNode evacuateFrom) {
+        removeProxies();
+        super.prepareDelete(evacuateFrom);
+    }
+
+    public void removeProxies() {
+        if (this.hasUsages()) {
+            outer: while (true) {
+                for (ProxyNode vpn : proxies().snapshot()) {
+                    ValueNode value = vpn.value();
+                    vpn.replaceAtUsagesAndDelete(value);
+                    if (value == this) {
+                        // Guard proxy could have this input as value.
+                        continue outer;
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public NodeIterable<ProxyNode> proxies() {
+        return (NodeIterable) usages().filter(n -> {
+            if (n instanceof ProxyNode) {
+                ProxyNode proxyNode = (ProxyNode) n;
+                return proxyNode.proxyPoint() == this;
+            }
+            return false;
+        });
+    }
+
+    @Override
     public void simplify(SimplifierTool tool) {
         Node prev = this.predecessor();
         while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, 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
@@ -27,6 +27,7 @@
 import jdk.vm.ci.meta.JavaKind;
 
 import com.oracle.graal.compiler.common.type.Stamp;
+import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.NodeInputList;
 import com.oracle.graal.graph.spi.Canonicalizable;
@@ -199,14 +200,26 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        ValueNode singleValue;
+
+        if (isLoopPhi()) {
+            if (singleBackValue() == this) {
+                return firstValue();
+            }
 
-        if (isLoopPhi() && singleBackValue() == this) {
-            singleValue = firstValue();
-        } else {
-            singleValue = singleValue();
+            boolean onlySelfUsage = true;
+            for (Node n : this.usages()) {
+                if (n != this) {
+                    onlySelfUsage = false;
+                    break;
+                }
+            }
+
+            if (onlySelfUsage) {
+                return null;
+            }
         }
 
+        ValueNode singleValue = singleValue();
         if (singleValue != MULTIPLE_VALUES) {
             return singleValue;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -230,8 +230,7 @@
         }
         if (!node.isDeleted()) {
             GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
-            node.replaceAtUsages(canonical);
-            node.safeDelete();
+            node.replaceAtUsagesAndDelete(canonical);
         }
         assert lookupNode(loopScope, nodeOrderId) == node;
         registerNode(loopScope, nodeOrderId, canonical, true, false);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Jan 05 16:42:05 2016 -0800
@@ -36,13 +36,18 @@
 import jdk.vm.ci.meta.SpeculationLog;
 import jdk.vm.ci.runtime.JVMCICompiler;
 
+import com.oracle.graal.compiler.common.cfg.BlockMap;
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.debug.JavaMethodContext;
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.NodeMap;
 import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodes.calc.FloatingNode;
+import com.oracle.graal.nodes.cfg.Block;
+import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.nodes.spi.VirtualizableAllocation;
 import com.oracle.graal.nodes.util.GraphUtil;
 
 /**
@@ -107,6 +112,34 @@
         }
     }
 
+    public static class ScheduleResult {
+        private final ControlFlowGraph cfg;
+        private final NodeMap<Block> nodeToBlockMap;
+        private final BlockMap<List<Node>> blockToNodesMap;
+
+        public ScheduleResult(ControlFlowGraph cfg, NodeMap<Block> nodeToBlockMap, BlockMap<List<Node>> blockToNodesMap) {
+            this.cfg = cfg;
+            this.nodeToBlockMap = nodeToBlockMap;
+            this.blockToNodesMap = blockToNodesMap;
+        }
+
+        public ControlFlowGraph getCFG() {
+            return cfg;
+        }
+
+        public NodeMap<Block> getNodeToBlockMap() {
+            return nodeToBlockMap;
+        }
+
+        public BlockMap<List<Node>> getBlockToNodesMap() {
+            return blockToNodesMap;
+        }
+
+        public List<Node> nodesFor(Block block) {
+            return blockToNodesMap.get(block);
+        }
+    }
+
     public static final long INVALID_GRAPH_ID = -1;
 
     private static final AtomicLong uniqueGraphIds = new AtomicLong();
@@ -126,6 +159,8 @@
 
     private final SpeculationLog speculationLog;
 
+    private ScheduleResult lastSchedule;
+
     /**
      * Records the methods that were inlined while constructing this graph, one entry for each time
      * a specific method is inlined.
@@ -182,6 +217,18 @@
         this.speculationLog = speculationLog;
     }
 
+    public void setLastSchedule(ScheduleResult result) {
+        lastSchedule = result;
+    }
+
+    public ScheduleResult getLastSchedule() {
+        return lastSchedule;
+    }
+
+    public void clearLastSchedule() {
+        setLastSchedule(null);
+    }
+
     public Stamp getReturnStamp() {
         Stamp returnStamp = null;
         for (ReturnNode returnNode : getNodes(ReturnNode.TYPE)) {
@@ -330,17 +377,6 @@
         return hasNode(LoopBeginNode.TYPE);
     }
 
-    public void removeFloating(FloatingNode node) {
-        assert node != null && node.isAlive() : "cannot remove " + node;
-        node.safeDelete();
-    }
-
-    public void replaceFloating(FloatingNode node, Node replacement) {
-        assert node != null && node.isAlive() && (replacement == null || replacement.isAlive()) : "cannot replace " + node + " with " + replacement;
-        node.replaceAtUsages(replacement);
-        node.safeDelete();
-    }
-
     /**
      * Unlinks a node from all its control flow neighbors and then removes it from its graph. The
      * node must have no {@linkplain Node#usages() usages}.
@@ -381,8 +417,7 @@
     public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         GraphUtil.unlinkFixedNode(node);
-        node.replaceAtUsages(replacement);
-        node.safeDelete();
+        node.replaceAtUsagesAndDelete(replacement);
     }
 
     public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
@@ -438,8 +473,7 @@
         assert survivingSuccessor != null;
         node.clearSuccessors();
         node.replaceAtPredecessor(survivingSuccessor);
-        node.replaceAtUsages(replacement);
-        node.safeDelete();
+        node.replaceAtUsagesAndDelete(replacement);
     }
 
     public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) {
@@ -480,8 +514,7 @@
         for (PhiNode phi : merge.phis().snapshot()) {
             assert phi.valueCount() == 1;
             ValueNode singleValue = phi.valueAt(0);
-            phi.replaceAtUsages(singleValue);
-            phi.safeDelete();
+            phi.replaceAtUsagesAndDelete(singleValue);
         }
         // remove loop exits
         if (merge instanceof LoopBeginNode) {
@@ -611,4 +644,25 @@
     public SpeculationLog getSpeculationLog() {
         return speculationLog;
     }
+
+    public final void clearAllStateAfter() {
+        for (Node node : getNodes()) {
+            if (node instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) node).stateAfter();
+                if (stateAfter != null) {
+                    ((StateSplit) node).setStateAfter(null);
+                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                }
+            }
+        }
+    }
+
+    public final boolean hasVirtualizableAllocation() {
+        for (Node n : getNodes()) {
+            if (n instanceof VirtualizableAllocation) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -100,8 +100,7 @@
 
         ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
         ConditionalNode value = graph().unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph()), equalValue));
-
-        graph().replaceFloating(this, value);
+        replaceAtUsagesAndDelete(value);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Tue Jan 05 16:42:05 2016 -0800
@@ -279,7 +279,9 @@
     }
 
     public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
-        return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+        GraphBuilderConfiguration config = new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins);
+        config.setUseProfiling(false);
+        return config;
     }
 
     public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -30,7 +30,7 @@
 
         <T> T getInjectedArgument(Class<T> type);
 
-        Stamp getReturnStamp(Class<?> type);
+        Stamp getReturnStamp(Class<?> type, boolean nonNull);
     }
 
     void registerPlugins(InvocationPlugins plugins, InjectionProvider injection);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.graal.compiler.common.type.IntegerStamp;
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ValueNode;
@@ -64,13 +62,4 @@
     public int dimensionCount() {
         return 1;
     }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        Stamp lengthStamp = length.stamp();
-        if (lengthStamp instanceof IntegerStamp && ((IntegerStamp) lengthStamp).isPositive()) {
-            // otherwise, removing the allocation might swallow a NegativeArraySizeException
-            super.simplify(tool);
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,20 +22,11 @@
  */
 package com.oracle.graal.nodes.java;
 
-import java.util.List;
-
 import com.oracle.graal.compiler.common.type.Stamp;
-import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
-import com.oracle.graal.graph.spi.Simplifiable;
-import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.DeoptimizingFixedWithNextNode;
-import com.oracle.graal.nodes.FixedWithNextNode;
 import com.oracle.graal.nodes.FrameState;
-import com.oracle.graal.nodes.extended.FixedValueAnchorNode;
-import com.oracle.graal.nodes.memory.WriteNode;
-import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
 import com.oracle.graal.nodes.spi.Lowerable;
 import com.oracle.graal.nodes.spi.LoweringTool;
 
@@ -43,7 +34,7 @@
  * The {@code AbstractNewObjectNode} is the base class for the new instance and new array nodes.
  */
 @NodeInfo
-public abstract class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
+public abstract class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Lowerable {
 
     public static final NodeClass<AbstractNewObjectNode> TYPE = NodeClass.create(AbstractNewObjectNode.class);
     protected final boolean fillContents;
@@ -61,56 +52,6 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        // poor man's escape analysis: check if the object can be trivially removed
-        for (Node usage : usages()) {
-            if (usage instanceof FixedValueAnchorNode) {
-                if (((FixedValueAnchorNode) usage).usages().isNotEmpty()) {
-                    return;
-                }
-            } else if (usage instanceof OffsetAddressNode) {
-                if (((OffsetAddressNode) usage).getBase() != this) {
-                    return;
-                }
-                for (Node access : usage.usages()) {
-                    if (access instanceof WriteNode) {
-                        if (access.usages().isNotEmpty()) {
-                            // we would need to fix up the memory graph if the write has usages
-                            return;
-                        }
-                    } else {
-                        return;
-                    }
-                }
-            } else {
-                return;
-            }
-        }
-        for (Node usage : usages().distinct().snapshot()) {
-            if (usage instanceof OffsetAddressNode) {
-                for (Node access : usage.usages().snapshot()) {
-                    removeUsage(tool, (FixedWithNextNode) access);
-                }
-            } else {
-                removeUsage(tool, (FixedWithNextNode) usage);
-            }
-        }
-        List<Node> snapshot = inputs().snapshot();
-        graph().removeFixed(this);
-        for (Node input : snapshot) {
-            tool.removeIfUnused(input);
-        }
-    }
-
-    private void removeUsage(SimplifierTool tool, FixedWithNextNode usage) {
-        List<Node> snapshot = usage.inputs().snapshot();
-        graph().removeFixed(usage);
-        for (Node input : snapshot) {
-            tool.removeIfUnused(input);
-        }
-    }
-
-    @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -33,7 +33,6 @@
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.spi.Canonicalizable;
 import com.oracle.graal.graph.spi.CanonicalizerTool;
-import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ValueNode;
@@ -87,15 +86,6 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        /*
-         * Do not call the super implementation: we must not eliminate unused allocations because
-         * throwing a NullPointerException or IllegalArgumentException is a possible side effect of
-         * an unused allocation.
-         */
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (elementType.isConstant()) {
             ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -32,7 +32,6 @@
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.spi.Canonicalizable;
 import com.oracle.graal.graph.spi.CanonicalizerTool;
-import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.ValueNode;
@@ -57,14 +56,6 @@
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        /*
-         * Do not call the super implementation: we must not eliminate unused allocations because
-         * throwing an InstantiationException is a possible side effect of an unused allocation.
-         */
-    }
-
-    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (clazz.isConstant()) {
             ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -37,7 +37,6 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeWorkList;
 import com.oracle.graal.graph.iterators.NodeIterable;
-import com.oracle.graal.graph.iterators.NodePredicate;
 import com.oracle.graal.graph.spi.SimplifierTool;
 import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.AbstractEndNode;
@@ -60,14 +59,6 @@
 
 public class GraphUtil {
 
-    private static final NodePredicate FLOATING = new NodePredicate() {
-
-        @Override
-        public final boolean apply(Node n) {
-            return !(n instanceof FixedNode);
-        }
-    };
-
     public static void killCFG(Node node, SimplifierTool tool) {
         assert node.isAlive();
         if (node instanceof AbstractEndNode) {
@@ -133,8 +124,8 @@
         }
     }
 
-    public static NodePredicate isFloatingNode() {
-        return FLOATING;
+    public static boolean isFloatingNode(Node n) {
+        return !(n instanceof FixedNode);
     }
 
     private static void propagateKill(Node node) {
@@ -223,7 +214,7 @@
         if (singleValue != PhiNode.MULTIPLE_VALUES) {
             Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
             Collection<ProxyNode> proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot();
-            phiNode.graph().replaceFloating(phiNode, singleValue);
+            phiNode.replaceAtUsagesAndDelete(singleValue);
             for (PhiNode phi : phiUsages) {
                 checkRedundantPhi(phi);
             }
@@ -250,7 +241,7 @@
                 if (vpnValue == v2) {
                     Collection<PhiNode> phiUsages = vpn.usages().filter(PhiNode.class).snapshot();
                     Collection<ProxyNode> proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot();
-                    vpn.graph().replaceFloating(vpn, vpnValue);
+                    vpn.replaceAtUsagesAndDelete(vpnValue);
                     for (PhiNode phi : phiUsages) {
                         checkRedundantPhi(phi);
                     }
@@ -496,7 +487,7 @@
     }
 
     public static boolean tryKillUnused(Node node) {
-        if (node.isAlive() && isFloatingNode().apply(node) && node.hasNoUsages()) {
+        if (node.isAlive() && isFloatingNode(node) && node.hasNoUsages()) {
             killWithUnusedFloatingInputs(node);
             return true;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options.processor/src/META-INF/services/javax.annotation.processing.Processor	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,1 @@
+com.oracle.graal.options.processor.OptionProcessor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/OptionProcessor.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options.processor;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.JavaFileObject;
+
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionDescriptors;
+import com.oracle.graal.options.OptionValue;
+
+/**
+ * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors}
+ * implementation is generated for each top level class containing at least one such field. The name
+ * of the generated class for top level class {@code com.foo.Bar} is
+ * {@code com.foo.Bar_OptionDescriptors}.
+ */
+@SupportedAnnotationTypes({"com.oracle.graal.options.Option"})
+public class OptionProcessor extends AbstractProcessor {
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private final Set<Element> processed = new HashSet<>();
+
+    private void processElement(Element element, OptionsInfo info) {
+
+        if (!element.getModifiers().contains(Modifier.STATIC)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element);
+            return;
+        }
+        if (element.getModifiers().contains(Modifier.PRIVATE)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be private", element);
+            return;
+        }
+
+        Option annotation = element.getAnnotation(Option.class);
+        assert annotation != null;
+        assert element instanceof VariableElement;
+        assert element.getKind() == ElementKind.FIELD;
+        VariableElement field = (VariableElement) element;
+        String fieldName = field.getSimpleName().toString();
+
+        Elements elements = processingEnv.getElementUtils();
+        Types types = processingEnv.getTypeUtils();
+
+        TypeMirror fieldType = field.asType();
+        if (fieldType.getKind() != TypeKind.DECLARED) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element);
+            return;
+        }
+        DeclaredType declaredFieldType = (DeclaredType) fieldType;
+
+        TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType();
+        if (!types.isSubtype(fieldType, types.erasure(optionValueType))) {
+            String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType);
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+            return;
+        }
+
+        if (!field.getModifiers().contains(Modifier.STATIC)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element);
+            return;
+        }
+        if (field.getModifiers().contains(Modifier.PRIVATE)) {
+            processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be private", element);
+            return;
+        }
+
+        String help = annotation.help();
+        if (help.length() != 0) {
+            char firstChar = help.charAt(0);
+            if (!Character.isUpperCase(firstChar)) {
+                processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element);
+                return;
+            }
+        }
+
+        String optionName = annotation.name();
+        if (optionName.equals("")) {
+            optionName = fieldName;
+        }
+
+        DeclaredType declaredOptionValueType = declaredFieldType;
+        while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) {
+            List<? extends TypeMirror> directSupertypes = types.directSupertypes(declaredFieldType);
+            assert !directSupertypes.isEmpty();
+            declaredOptionValueType = (DeclaredType) directSupertypes.get(0);
+        }
+
+        assert !declaredOptionValueType.getTypeArguments().isEmpty();
+        String optionType = declaredOptionValueType.getTypeArguments().get(0).toString();
+        if (optionType.startsWith("java.lang.")) {
+            optionType = optionType.substring("java.lang.".length());
+        }
+
+        Element enclosing = element.getEnclosingElement();
+        String declaringClass = "";
+        String separator = "";
+        Set<Element> originatingElementsList = info.originatingElements;
+        originatingElementsList.add(field);
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
+                    String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+                    processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
+                    return;
+                }
+                originatingElementsList.add(enclosing);
+                declaringClass = enclosing.getSimpleName() + separator + declaringClass;
+                separator = ".";
+            } else {
+                assert enclosing.getKind() == ElementKind.PACKAGE;
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+
+        info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field));
+    }
+
+    private void createFiles(OptionsInfo info) {
+        String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
+        Name topDeclaringClass = info.topDeclaringType.getSimpleName();
+        Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
+
+        createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements);
+    }
+
+    private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) {
+        String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName();
+
+        Filer filer = processingEnv.getFiler();
+        try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) {
+
+            out.println("// CheckStyle: stop header check");
+            out.println("// CheckStyle: stop line length check");
+            out.println("// GENERATED CONTENT - DO NOT EDIT");
+            out.println("// Source: " + topDeclaringClass + ".java");
+            out.println("package " + pkg + ";");
+            out.println("");
+            out.println("import java.util.*;");
+            out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;");
+            out.println("");
+            out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {");
+
+            String desc = OptionDescriptor.class.getSimpleName();
+
+            int i = 0;
+            Collections.sort(info.options);
+
+            out.println("    @Override");
+            out.println("    public OptionDescriptor get(String value) {");
+            out.println("        // CheckStyle: stop line length check");
+            if (info.options.size() == 1) {
+                out.println("        if (value.equals(\"" + info.options.get(0).name + "\")) {");
+            } else {
+                out.println("        switch (value) {");
+            }
+            for (OptionInfo option : info.options) {
+                String name = option.name;
+                String optionValue;
+                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
+                    throw new InternalError();
+                } else {
+                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
+                }
+                String type = option.type;
+                String help = option.help;
+                String declaringClass = option.declaringClass;
+                Name fieldName = option.field.getSimpleName();
+                if (info.options.size() == 1) {
+                    out.printf("            return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue);
+                } else {
+                    out.printf("            case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue);
+                }
+            }
+            out.println("        }");
+            out.println("        // CheckStyle: resume line length check");
+            out.println("        return null;");
+            out.println("    }");
+            out.println();
+            out.println("    @Override");
+            out.println("    public Iterator<" + desc + "> iterator() {");
+            out.println("        // CheckStyle: stop line length check");
+            out.println("        List<" + desc + "> options = Arrays.asList(");
+            for (OptionInfo option : info.options) {
+                String optionValue;
+                if (option.field.getModifiers().contains(Modifier.PRIVATE)) {
+                    throw new InternalError();
+                } else {
+                    optionValue = option.declaringClass + "." + option.field.getSimpleName();
+                }
+                String name = option.name;
+                String type = option.type;
+                String help = option.help;
+                String declaringClass = option.declaringClass;
+                Name fieldName = option.field.getSimpleName();
+                String comma = i == info.options.size() - 1 ? "" : ",";
+                out.printf("            %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma);
+                i++;
+            }
+            out.println("        );");
+            out.println("        // CheckStyle: resume line length check");
+            out.println("        return options.iterator();");
+            out.println("    }");
+            out.println("}");
+        }
+    }
+
+    protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
+        try {
+            // Ensure Unix line endings to comply with code style guide checked by Checkstyle
+            JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements);
+            return new PrintWriter(sourceFile.openWriter()) {
+
+                @Override
+                public void println() {
+                    print("\n");
+                }
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static class OptionInfo implements Comparable<OptionInfo> {
+
+        final String name;
+        final String help;
+        final String type;
+        final String declaringClass;
+        final VariableElement field;
+
+        public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) {
+            this.name = name;
+            this.help = help;
+            this.type = type;
+            this.declaringClass = declaringClass;
+            this.field = field;
+        }
+
+        @Override
+        public int compareTo(OptionInfo other) {
+            return name.compareTo(other.name);
+        }
+
+        @Override
+        public String toString() {
+            return declaringClass + "." + field;
+        }
+    }
+
+    static class OptionsInfo {
+
+        final Element topDeclaringType;
+        final List<OptionInfo> options = new ArrayList<>();
+        final Set<Element> originatingElements = new HashSet<>();
+
+        public OptionsInfo(Element topDeclaringType) {
+            this.topDeclaringType = topDeclaringType;
+        }
+    }
+
+    private static Element topDeclaringType(Element element) {
+        Element enclosing = element.getEnclosingElement();
+        if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) {
+            assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE;
+            return element;
+        }
+        return topDeclaringType(enclosing);
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        Map<Element, OptionsInfo> map = new HashMap<>();
+        for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) {
+            if (!processed.contains(element)) {
+                processed.add(element);
+                Element topDeclaringType = topDeclaringType(element);
+                OptionsInfo options = map.get(topDeclaringType);
+                if (options == null) {
+                    options = new OptionsInfo(topDeclaringType);
+                    map.put(topDeclaringType, options);
+                }
+                processElement(element, options);
+            }
+        }
+
+        boolean ok = true;
+        Map<String, OptionInfo> uniqueness = new HashMap<>();
+        for (OptionsInfo info : map.values()) {
+            for (OptionInfo option : info.options) {
+                OptionInfo conflict = uniqueness.put(option.name, option);
+                if (conflict != null) {
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field);
+                    ok = false;
+                }
+            }
+        }
+
+        if (ok) {
+            for (OptionsInfo info : map.values()) {
+                createFiles(info);
+            }
+        }
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/NestedBooleanOptionValueTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @run junit jdk.vm.ci.options.test.NestedBooleanOptionValueTest
+ */
+
+package com.oracle.graal.options.test;
+
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.Master0;
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.Master1;
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.Master2;
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.NestedOption0;
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.NestedOption1;
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.NestedOption2;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.oracle.graal.options.NestedBooleanOptionValue;
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
+
+public class NestedBooleanOptionValueTest {
+
+    public static class Options {
+        public static final OptionValue<Boolean> Master0 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption0 = new NestedBooleanOptionValue(Master0, true);
+        public static final OptionValue<Boolean> Master1 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption1 = new NestedBooleanOptionValue(Master1, true);
+        public static final OptionValue<Boolean> Master2 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption2 = new NestedBooleanOptionValue(Master2, false);
+    }
+
+    static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0);
+    static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0);
+    static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1);
+    static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1);
+    static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2);
+    static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2);
+
+    @SuppressWarnings("try")
+    @Test
+    public void runOverrides() {
+        assertTrue(Master0.getValue());
+        assertTrue(NestedOption0.getValue());
+        try (OverrideScope s1 = OptionValue.override(Master0, false)) {
+            assertFalse(Master0.getValue());
+            assertFalse(NestedOption0.getValue());
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) {
+                assertFalse(NestedOption0.getValue());
+            }
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) {
+                assertTrue(NestedOption0.getValue());
+            }
+        }
+        assertTrue(Master0.getValue());
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) {
+            assertFalse(NestedOption0.getValue());
+        }
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) {
+            assertTrue(NestedOption0.getValue());
+        }
+    }
+
+    @Test
+    public void runDefaultTrue() {
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        // nested value unset
+        Master1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set false
+        Master1.setValue(false);
+        NestedOption1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set true
+        Master1.setValue(false);
+        NestedOption1.setValue(true);
+        assertFalse(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+    }
+
+    @Test
+    public void runDefaultFalse() {
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // nested value unset
+        Master2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set false
+        Master2.setValue(false);
+        NestedOption2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set true
+        Master2.setValue(false);
+        NestedOption2.setValue(true);
+        assertFalse(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/TestOptionValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @run junit com.oracle.graal.options.test.TestOptionValue
+ */
+
+package com.oracle.graal.options.test;
+
+import static com.oracle.graal.options.test.TestOptionValue.Options.Mutable;
+import static com.oracle.graal.options.test.TestOptionValue.Options.SecondMutable;
+import static com.oracle.graal.options.test.TestOptionValue.Options.Stable;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
+
+@SuppressWarnings("try")
+public class TestOptionValue {
+
+    public static class Options {
+        public static final OptionValue<Boolean> Stable = new StableOptionValue<>(true);
+        public static final OptionValue<String> Mutable = new OptionValue<>("original");
+        public static final OptionValue<String> SecondMutable = new OptionValue<>("second");
+    }
+
+    static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable);
+    static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable);
+    static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable);
+
+    @Test
+    public void testMutable() {
+        assertEquals("original", Mutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals("override1", Mutable.getValue());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals("override2", Mutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) {
+                assertEquals("override3", Mutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+        }
+        assertEquals("original", Mutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "original")) {
+            assertEquals("original", Mutable.getValue());
+        }
+    }
+
+    @Test
+    public void testMultiple() {
+        assertEquals("original", Mutable.getValue());
+        assertEquals("second", SecondMutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) {
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) {
+                assertEquals("override2", Mutable.getValue());
+                assertEquals("secondOverride2", SecondMutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+            try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) {
+                assertEquals("override3", Mutable.getValue());
+                assertEquals("secondOverride3", SecondMutable.getValue());
+            }
+            assertEquals("override1", Mutable.getValue());
+            assertEquals("secondOverride1", SecondMutable.getValue());
+        }
+        assertEquals("original", Mutable.getValue());
+        assertEquals("second", SecondMutable.getValue());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) {
+            assertEquals("original", Mutable.getValue());
+            assertEquals("second", SecondMutable.getValue());
+        }
+    }
+
+    @Test
+    public void testStable() {
+        assertTrue(Stable.getValue());
+        try (OverrideScope s = OptionValue.override(Stable, false)) {
+            fail("cannot override stable option");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void toStringTest() {
+        assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString());
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString());
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals("com.oracle.graal.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString());
+            }
+        }
+    }
+
+    @Test
+    public void getValuesTest() {
+        assertEquals(Arrays.asList("original"), Mutable.getValues(null));
+        assertEquals(Arrays.asList(true), Stable.getValues(null));
+        try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) {
+            assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null));
+            try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) {
+                assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/DerivedOptionValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+import com.oracle.graal.options.OptionValue.OverrideScope;
+
+/**
+ * A cached value that needs to be recomputed when an option changes.
+ */
+public class DerivedOptionValue<T> {
+
+    public interface OptionSupplier<T> extends Supplier<T>, Serializable {
+    }
+
+    private final T initialValue;
+    private final OptionSupplier<T> supplier;
+
+    public DerivedOptionValue(OptionSupplier<T> supplier) {
+        this.supplier = supplier;
+        assert OptionValue.getOverrideScope() == null : "derived option value should be initialized outside any override scope";
+        this.initialValue = createValue();
+    }
+
+    public T getValue() {
+        OverrideScope overrideScope = OptionValue.getOverrideScope();
+        if (overrideScope != null) {
+            return overrideScope.getDerived(this);
+        } else {
+            return initialValue;
+        }
+    }
+
+    T createValue() {
+        return supplier.get();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/GraalJarsOptionDescriptorsProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import com.oracle.graal.options.OptionsParser.OptionDescriptorsProvider;
+
+/**
+ * Access to the {@link OptionDescriptors} declared by
+ * {@code META-INF/services/com.oracle.graal.options.OptionDescriptors} files in
+ * {@code <jre>/lib/jvmci/*.jar}.
+ */
+public final class GraalJarsOptionDescriptorsProvider implements OptionDescriptorsProvider {
+
+    static final String OptionDescriptorsServiceFile = "META-INF/services/" + OptionDescriptors.class.getName();
+
+    private final Iterator<File> jars;
+    private final List<OptionDescriptors> optionsDescriptorsList;
+
+    /**
+     * Creates a {@link GraalJarsOptionDescriptorsProvider} if at least one JVMCI jar is available
+     * otherwise returns null.
+     */
+    public static GraalJarsOptionDescriptorsProvider create() {
+        List<File> jarsList = findJVMCIJars();
+        if (jarsList.isEmpty()) {
+            return null;
+        }
+        return new GraalJarsOptionDescriptorsProvider(jarsList);
+    }
+
+    private GraalJarsOptionDescriptorsProvider(List<File> jarsList) {
+        this.jars = jarsList.iterator();
+        this.optionsDescriptorsList = new ArrayList<>(jarsList.size() * 3);
+    }
+
+    /**
+     * Finds the list of JVMCI jars.
+     */
+    private static List<File> findJVMCIJars() {
+        File javaHome = new File(System.getProperty("java.home"));
+        File lib = new File(javaHome, "lib");
+        File jvmci = new File(lib, "jvmci");
+        if (!jvmci.exists()) {
+            return Collections.emptyList();
+        }
+
+        List<File> jarFiles = new ArrayList<>();
+        for (String fileName : jvmci.list()) {
+            if (fileName.endsWith(".jar")) {
+                File file = new File(jvmci, fileName);
+                if (file.isDirectory()) {
+                    continue;
+                }
+                jarFiles.add(file);
+            }
+        }
+        return jarFiles;
+    }
+
+    public OptionDescriptor get(String name) {
+        // Look up loaded option descriptors first
+        for (OptionDescriptors optionDescriptors : optionsDescriptorsList) {
+            OptionDescriptor desc = optionDescriptors.get(name);
+            if (desc != null) {
+                return desc;
+            }
+        }
+        while (jars.hasNext()) {
+            File path = jars.next();
+            try (JarFile jar = new JarFile(path)) {
+                ZipEntry entry = jar.getEntry(OptionDescriptorsServiceFile);
+                if (entry != null) {
+                    BufferedReader br = new BufferedReader(new InputStreamReader(jar.getInputStream(entry)));
+                    String line = null;
+                    OptionDescriptor desc = null;
+                    while ((line = br.readLine()) != null) {
+                        OptionDescriptors options;
+                        try {
+                            options = (OptionDescriptors) Class.forName(line).newInstance();
+                            optionsDescriptorsList.add(options);
+                            if (desc == null) {
+                                desc = options.get(name);
+                            }
+                        } catch (Exception e) {
+                            throw new InternalError("Error instantiating class " + line + " read from " + path, e);
+                        }
+                    }
+                    if (desc != null) {
+                        return desc;
+                    }
+                }
+            } catch (IOException e) {
+                throw new InternalError("Error reading " + path, e);
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/NestedBooleanOptionValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+/**
+ * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master
+ * option}.
+ * <p>
+ * <li>If the option is present on the command line the specified value is used.
+ * <li>Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows:
+ * <ul>
+ * <li>If {@link #masterOption} is set, this value equals to {@link #initialValue}.
+ * <li>Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}.
+ */
+public class NestedBooleanOptionValue extends OptionValue<Boolean> {
+    private final OptionValue<Boolean> masterOption;
+    private final Boolean initialValue;
+
+    public NestedBooleanOptionValue(OptionValue<Boolean> masterOption, Boolean initialValue) {
+        super(null);
+        this.masterOption = masterOption;
+        this.initialValue = initialValue;
+    }
+
+    public OptionValue<Boolean> getMasterOption() {
+        return masterOption;
+    }
+
+    @Override
+    public Boolean getValue() {
+        Boolean v = super.getValue();
+        if (v == null) {
+            return initialValue && masterOption.getValue();
+        }
+        return v;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/Option.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Describes the attributes of an option whose {@link OptionValue value} is in a static field
+ * annotated by this annotation type.
+ *
+ * @see OptionDescriptor
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.FIELD)
+public @interface Option {
+
+    /**
+     * Gets a help message for the option. New lines can be embedded in the message with
+     * {@code "%n"}.
+     */
+    String help();
+
+    /**
+     * The name of the option. By default, the name of the annotated field should be used.
+     */
+    String name() default "";
+
+    /**
+     * Specifies the type of the option.
+     */
+    OptionType type() default OptionType.Debug;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptor.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+/**
+ * Describes the attributes of a static field {@linkplain Option option} and provides access to its
+ * {@linkplain OptionValue value}.
+ */
+public final class OptionDescriptor {
+
+    protected final String name;
+    protected final Class<?> type;
+    protected final String help;
+    protected final OptionValue<?> option;
+    protected final Class<?> declaringClass;
+    protected final String fieldName;
+
+    public static OptionDescriptor create(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionValue<?> option) {
+        OptionDescriptor result = option.getDescriptor();
+        if (result == null) {
+            result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option);
+            option.setDescriptor(result);
+        }
+        assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option;
+        return result;
+    }
+
+    private OptionDescriptor(String name, Class<?> type, String help, Class<?> declaringClass, String fieldName, OptionValue<?> option) {
+        this.name = name;
+        this.type = type;
+        this.help = help;
+        this.option = option;
+        this.declaringClass = declaringClass;
+        this.fieldName = fieldName;
+        assert !type.isPrimitive() : "must used boxed type instead of " + type;
+    }
+
+    /**
+     * Gets the type of values stored in the option. This will be the boxed type for a primitive
+     * option.
+     */
+    public Class<?> getType() {
+        return type;
+    }
+
+    /**
+     * Gets a descriptive help message for the option.
+     */
+    public String getHelp() {
+        return help;
+    }
+
+    /**
+     * Gets the name of the option. It's up to the client of this object how to use the name to get
+     * a user specified value for the option from the environment.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the boxed option value.
+     */
+    public OptionValue<?> getOptionValue() {
+        return option;
+    }
+
+    public Class<?> getDeclaringClass() {
+        return declaringClass;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    /**
+     * Gets a description of the location where this option is stored.
+     */
+    public String getLocation() {
+        return getDeclaringClass().getName() + "." + getFieldName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptors.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+/**
+ * An interface to a set of {@link OptionDescriptor}s.
+ */
+public interface OptionDescriptors extends Iterable<OptionDescriptor> {
+    /**
+     * Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option
+     * descriptor set doesn't contain a matching option.
+     */
+    OptionDescriptor get(String value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionType.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+/**
+ * Classifies Graal options in several categories depending on who this option is relevant for.
+ *
+ */
+public enum OptionType {
+    /**
+     * An option common for users to apply.
+     */
+    User,
+
+    /**
+     * An option only relevant in corner cases and for fine-tuning.
+     */
+    Expert,
+
+    /**
+     * An option only relevant when debugging the compiler.
+     */
+    Debug
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+/**
+ * An option value.
+ */
+public class OptionValue<T> {
+    /**
+     * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of
+     * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the
+     * object returned by this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * try (OverrideScope s = OptionValue.override(myOption, myValue) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     */
+    public static OverrideScope override(OptionValue<?> option, Object value) {
+        OverrideScope current = getOverrideScope();
+        if (current == null) {
+            if (!value.equals(option.getValue())) {
+                return new SingleOverrideScope(option, value);
+            }
+            Map<OptionValue<?>, Object> overrides = Collections.emptyMap();
+            return new MultipleOverridesScope(current, overrides);
+        }
+        return new MultipleOverridesScope(current, option, value);
+    }
+
+    /**
+     * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue()
+     * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value}
+     * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by
+     * this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * Map&lt;OptionValue, Object&gt; overrides = new HashMap&lt;&gt;();
+     * overrides.put(myOption1, myValue1);
+     * overrides.put(myOption2, myValue2);
+     * try (OverrideScope s = OptionValue.override(overrides) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     */
+    public static OverrideScope override(Map<OptionValue<?>, Object> overrides) {
+        OverrideScope current = getOverrideScope();
+        if (current == null && overrides.size() == 1) {
+            Entry<OptionValue<?>, Object> single = overrides.entrySet().iterator().next();
+            OptionValue<?> option = single.getKey();
+            Object overrideValue = single.getValue();
+            if (!overrideValue.equals(option.getValue())) {
+                return new SingleOverrideScope(option, overrideValue);
+            }
+        }
+        return new MultipleOverridesScope(current, overrides);
+    }
+
+    /**
+     * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue()
+     * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value}
+     * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by
+     * this method.
+     * <p>
+     * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be
+     * used:
+     *
+     * <pre>
+     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
+     *     // code that depends on myOption == myValue
+     * }
+     * </pre>
+     *
+     * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]}
+     */
+    public static OverrideScope override(Object... overrides) {
+        OverrideScope current = getOverrideScope();
+        if (current == null && overrides.length == 2) {
+            OptionValue<?> option = (OptionValue<?>) overrides[0];
+            Object overrideValue = overrides[1];
+            if (!overrideValue.equals(option.getValue())) {
+                return new SingleOverrideScope(option, overrideValue);
+            }
+        }
+        Map<OptionValue<?>, Object> map = Collections.emptyMap();
+        for (int i = 0; i < overrides.length; i += 2) {
+            OptionValue<?> option = (OptionValue<?>) overrides[i];
+            Object overrideValue = overrides[i + 1];
+            if (!overrideValue.equals(option.getValue())) {
+                if (map.isEmpty()) {
+                    map = new HashMap<>();
+                }
+                map.put(option, overrideValue);
+            }
+        }
+        return new MultipleOverridesScope(current, map);
+    }
+
+    private static final ThreadLocal<OverrideScope> overrideScopeTL = new ThreadLocal<>();
+
+    protected static OverrideScope getOverrideScope() {
+        return overrideScopeTL.get();
+    }
+
+    protected static void setOverrideScope(OverrideScope overrideScope) {
+        overrideScopeTL.set(overrideScope);
+    }
+
+    private T defaultValue;
+
+    /**
+     * The raw option value.
+     */
+    protected T value;
+
+    private OptionDescriptor descriptor;
+
+    private long reads;
+    private OptionValue<?> next;
+    private static OptionValue<?> head;
+
+    private static final boolean ShowReadsHistogram = Boolean.getBoolean("graal.showOptionValueReadsHistogram");
+
+    private static void addToHistogram(OptionValue<?> option) {
+        if (ShowReadsHistogram) {
+            synchronized (OptionValue.class) {
+                option.next = head;
+                head = option;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public OptionValue(T value) {
+        this.defaultValue = value;
+        this.value = (T) DEFAULT;
+        addToHistogram(this);
+    }
+
+    private static final Object DEFAULT = "DEFAULT";
+    private static final Object UNINITIALIZED = "UNINITIALIZED";
+
+    /**
+     * Creates an uninitialized option value for a subclass that initializes itself
+     * {@link #defaultValue() lazily}.
+     */
+    @SuppressWarnings("unchecked")
+    protected OptionValue() {
+        this.defaultValue = (T) UNINITIALIZED;
+        this.value = (T) DEFAULT;
+        addToHistogram(this);
+    }
+
+    /**
+     * Lazy initialization of default value.
+     */
+    protected T defaultValue() {
+        throw new InternalError("Option without a default value value must override defaultValue()");
+    }
+
+    /**
+     * Sets the descriptor for this option.
+     */
+    public void setDescriptor(OptionDescriptor descriptor) {
+        assert this.descriptor == null : "Overwriting existing descriptor";
+        this.descriptor = descriptor;
+    }
+
+    /**
+     * Returns the descriptor for this option, if it has been set by
+     * {@link #setDescriptor(OptionDescriptor)}.
+     */
+    public OptionDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Gets the name of this option. The name for an option value with a null
+     * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of
+     * {@link Object#toString()}.
+     */
+    public String getName() {
+        return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName());
+    }
+
+    @Override
+    public String toString() {
+        return getName() + "=" + getValue();
+    }
+
+    /**
+     * The initial value specified in source code. The returned value is not affected by calls to
+     * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not
+     * affected by options set on the command line.
+     */
+    public T getDefaultValue() {
+        if (defaultValue == UNINITIALIZED) {
+            defaultValue = defaultValue();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns true if the option has the same value that was set in the source code.
+     */
+    public boolean hasDefaultValue() {
+        if (!(this instanceof StableOptionValue)) {
+            getValue(); // ensure initialized
+        }
+        return value == DEFAULT || Objects.equals(value, getDefaultValue());
+    }
+
+    /**
+     * Gets the value of this option.
+     */
+    public T getValue() {
+        if (ShowReadsHistogram) {
+            reads++;
+        }
+        if (!(this instanceof StableOptionValue)) {
+            OverrideScope overrideScope = getOverrideScope();
+            if (overrideScope != null) {
+                T override = overrideScope.getOverride(this);
+                if (override != null) {
+                    return override;
+                }
+            }
+        }
+        if (value != DEFAULT) {
+            return value;
+        } else {
+            return getDefaultValue();
+        }
+    }
+
+    /**
+     * Gets the values of this option including overridden values.
+     *
+     * @param c the collection to which the values are added. If null, one is allocated.
+     * @return the collection to which the values were added in order from most overridden to
+     *         current value
+     */
+    @SuppressWarnings("unchecked")
+    public Collection<T> getValues(Collection<T> c) {
+        Collection<T> values = c == null ? new ArrayList<>() : c;
+        if (!(this instanceof StableOptionValue)) {
+            OverrideScope overrideScope = getOverrideScope();
+            if (overrideScope != null) {
+                overrideScope.getOverrides(this, (Collection<Object>) values);
+            }
+        }
+        if (value != DEFAULT) {
+            values.add(value);
+        } else {
+            values.add(getDefaultValue());
+        }
+        return values;
+    }
+
+    /**
+     * Sets the value of this option.
+     */
+    @SuppressWarnings("unchecked")
+    public void setValue(Object v) {
+        this.value = (T) v;
+    }
+
+    /**
+     * An object whose {@link #close()} method reverts the option value overriding initiated by
+     * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}.
+     */
+    public abstract static class OverrideScope implements AutoCloseable {
+
+        private Map<DerivedOptionValue<?>, Object> derivedCache = null;
+
+        public <T> T getDerived(DerivedOptionValue<T> key) {
+            if (derivedCache == null) {
+                derivedCache = new HashMap<>();
+            }
+            @SuppressWarnings("unchecked")
+            T ret = (T) derivedCache.get(key);
+            if (ret == null) {
+                ret = key.createValue();
+                derivedCache.put(key, ret);
+            }
+            return ret;
+        }
+
+        abstract void addToInherited(Map<OptionValue<?>, Object> inherited);
+
+        abstract <T> T getOverride(OptionValue<T> option);
+
+        abstract void getOverrides(OptionValue<?> option, Collection<Object> c);
+
+        public abstract void close();
+    }
+
+    static class SingleOverrideScope extends OverrideScope {
+
+        private final OptionValue<?> option;
+        private final Object value;
+
+        public SingleOverrideScope(OptionValue<?> option, Object value) {
+            if (option instanceof StableOptionValue) {
+                throw new IllegalArgumentException("Cannot override stable option " + option);
+            }
+            this.option = option;
+            this.value = value;
+            setOverrideScope(this);
+        }
+
+        @Override
+        void addToInherited(Map<OptionValue<?>, Object> inherited) {
+            inherited.put(option, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        <T> T getOverride(OptionValue<T> key) {
+            if (key == this.option) {
+                return (T) value;
+            }
+            return null;
+        }
+
+        @Override
+        void getOverrides(OptionValue<?> key, Collection<Object> c) {
+            if (key == this.option) {
+                c.add(value);
+            }
+        }
+
+        @Override
+        public void close() {
+            setOverrideScope(null);
+        }
+    }
+
+    static class MultipleOverridesScope extends OverrideScope {
+        final OverrideScope parent;
+        final Map<OptionValue<?>, Object> overrides;
+
+        public MultipleOverridesScope(OverrideScope parent, OptionValue<?> option, Object value) {
+            this.parent = parent;
+            this.overrides = new HashMap<>();
+            if (parent != null) {
+                parent.addToInherited(overrides);
+            }
+            if (option instanceof StableOptionValue) {
+                throw new IllegalArgumentException("Cannot override stable option " + option);
+            }
+            if (!value.equals(option.getValue())) {
+                this.overrides.put(option, value);
+            }
+            if (!overrides.isEmpty()) {
+                setOverrideScope(this);
+            }
+        }
+
+        MultipleOverridesScope(OverrideScope parent, Map<OptionValue<?>, Object> overrides) {
+            this.parent = parent;
+            if (overrides.isEmpty() && parent == null) {
+                this.overrides = Collections.emptyMap();
+                return;
+            }
+            this.overrides = new HashMap<>();
+            if (parent != null) {
+                parent.addToInherited(this.overrides);
+            }
+            for (Map.Entry<OptionValue<?>, Object> e : overrides.entrySet()) {
+                OptionValue<?> option = e.getKey();
+                if (option instanceof StableOptionValue) {
+                    throw new IllegalArgumentException("Cannot override stable option " + option);
+                }
+                if (!e.getValue().equals(option.getValue())) {
+                    this.overrides.put(option, e.getValue());
+                }
+            }
+            if (!this.overrides.isEmpty()) {
+                setOverrideScope(this);
+            }
+        }
+
+        @Override
+        void addToInherited(Map<OptionValue<?>, Object> inherited) {
+            if (parent != null) {
+                parent.addToInherited(inherited);
+            }
+            inherited.putAll(overrides);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        <T> T getOverride(OptionValue<T> option) {
+            return (T) overrides.get(option);
+        }
+
+        @Override
+        void getOverrides(OptionValue<?> option, Collection<Object> c) {
+            Object v = overrides.get(option);
+            if (v != null) {
+                c.add(v);
+            }
+            if (parent != null) {
+                parent.getOverrides(option, c);
+            }
+        }
+
+        @Override
+        public void close() {
+            if (!overrides.isEmpty()) {
+                setOverrideScope(parent);
+            }
+        }
+    }
+
+    static {
+        if (ShowReadsHistogram) {
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                @Override
+                public void run() {
+                    ArrayList<OptionValue<?>> options = new ArrayList<>();
+                    for (OptionValue<?> option = head; option != null; option = option.next) {
+                        options.add(option);
+                    }
+                    Collections.sort(options, new Comparator<OptionValue<?>>() {
+
+                        public int compare(OptionValue<?> o1, OptionValue<?> o2) {
+                            if (o1.reads < o2.reads) {
+                                return -1;
+                            } else if (o1.reads > o2.reads) {
+                                return 1;
+                            } else {
+                                return o1.getName().compareTo(o2.getName());
+                            }
+                        }
+                    });
+                    PrintStream out = System.out;
+                    out.println("=== OptionValue reads histogram ===");
+                    for (OptionValue<?> option : options) {
+                        out.println(option.reads + "\t" + option);
+                    }
+                }
+            });
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionsLoader.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+/**
+ * Helper class used to load option descriptors. Only to be used in the slow-path.
+ */
+public class OptionsLoader {
+    public static final Map<String, OptionDescriptor> options = new HashMap<>();
+
+    /**
+     * Initializes {@link #options} from {@link Options} services.
+     */
+    static {
+        for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, OptionsLoader.class.getClassLoader())) {
+            for (OptionDescriptor desc : opts) {
+                String name = desc.getName();
+                OptionDescriptor existing = options.put(name, desc);
+                assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionsParser.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * This class contains methods for parsing Graal options and matching them against a set of
+ * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded from Graal jars, either
+ * {@linkplain GraalJarsOptionDescriptorsProvider directly} or via a {@link ServiceLoader}.
+ */
+public class OptionsParser {
+
+    private static final OptionValue<Boolean> PrintFlags = new OptionValue<>(false);
+    private static final OptionValue<Boolean> ShowFlags = new OptionValue<>(false);
+
+    /**
+     * A service for looking up {@link OptionDescriptor}s.
+     */
+    public interface OptionDescriptorsProvider {
+        /**
+         * Gets the {@link OptionDescriptor} matching a given option {@linkplain Option#name() name}
+         * or null if no option of that name is provided by this object.
+         */
+        OptionDescriptor get(String name);
+    }
+
+    public interface OptionConsumer {
+        void set(OptionDescriptor desc, Object value);
+    }
+
+    /**
+     * Parses a map representing assignments of values to options.
+     *
+     * @param optionSettings option settings (i.e., assignments of values to options)
+     * @param setter the object to notify of the parsed option and value
+     * @param odp if non-null, the service to use for looking up {@link OptionDescriptor}s
+     * @param options the options database to use if {@code odp == null}. If
+     *            {@code options == null && odp == null}, {@link OptionsLoader#options} is used.
+     * @throws IllegalArgumentException if there's a problem parsing {@code option}
+     */
+    public static void parseOptions(Map<String, String> optionSettings, OptionConsumer setter, OptionDescriptorsProvider odp, Map<String, OptionDescriptor> options) {
+        if (optionSettings != null && !optionSettings.isEmpty()) {
+
+            for (Map.Entry<String, String> e : optionSettings.entrySet()) {
+                parseOption(e.getKey(), e.getValue(), setter, odp, options);
+            }
+            if (PrintFlags.getValue() || ShowFlags.getValue()) {
+                printFlags(resolveOptions(options), "Graal", System.out, optionSettings.keySet());
+                if (PrintFlags.getValue()) {
+                    System.exit(0);
+                }
+            }
+        }
+    }
+
+    /**
+     * Parses a given option setting string to a map of settings.
+     *
+     * @param optionSetting a string matching the pattern {@code <name>=<value>}
+     */
+    public static void parseOptionSettingTo(String optionSetting, Map<String, String> dst) {
+        int eqIndex = optionSetting.indexOf('=');
+        if (eqIndex == -1) {
+            throw new InternalError("Option setting has does not match the pattern <name>=<value>: " + optionSetting);
+        }
+        dst.put(optionSetting.substring(0, eqIndex), optionSetting.substring(eqIndex + 1));
+    }
+
+    /**
+     * Resolves {@code options} to a non-null value. This ensures {@link OptionsLoader#options} is
+     * only loaded if necessary.
+     */
+    private static Map<String, OptionDescriptor> resolveOptions(Map<String, OptionDescriptor> options) {
+        return options != null ? options : OptionsLoader.options;
+    }
+
+    /**
+     * Parses a given option name and value.
+     *
+     * @param name the option name
+     * @param valueString the option value as a string
+     * @param setter the object to notify of the parsed option and value
+     * @param odp if non-null, the service to use for looking up {@link OptionDescriptor}s
+     * @param options the options database to use if {@code odp == null}. If
+     *            {@code options == null && odp == null}, {@link OptionsLoader#options} is used.
+     * @throws IllegalArgumentException if there's a problem parsing {@code option}
+     */
+    private static void parseOption(String name, String valueString, OptionConsumer setter, OptionDescriptorsProvider odp, Map<String, OptionDescriptor> options) {
+
+        OptionDescriptor desc = odp != null ? odp.get(name) : resolveOptions(options).get(name);
+        if (desc == null) {
+            if (name.equals("PrintFlags")) {
+                desc = OptionDescriptor.create("PrintFlags", Boolean.class, "Prints all Graal flags and exits", OptionsParser.class, "PrintFlags", PrintFlags);
+            } else if (name.equals("ShowFlags")) {
+                desc = OptionDescriptor.create("ShowFlags", Boolean.class, "Prints all Graal flags and continues", OptionsParser.class, "ShowFlags", ShowFlags);
+            }
+        }
+        if (desc == null) {
+            List<OptionDescriptor> matches = fuzzyMatch(resolveOptions(options), name);
+            Formatter msg = new Formatter();
+            msg.format("Could not find option %s", name);
+            if (!matches.isEmpty()) {
+                msg.format("%nDid you mean one of the following?");
+                for (OptionDescriptor match : matches) {
+                    msg.format("%n    %s=<value>", match.getName());
+                }
+            }
+            throw new IllegalArgumentException(msg.toString());
+        }
+
+        Class<?> optionType = desc.getType();
+        Object value;
+        if (optionType == Boolean.class) {
+            if ("true".equals(valueString)) {
+                value = Boolean.TRUE;
+            } else if ("false".equals(valueString)) {
+                value = Boolean.FALSE;
+            } else {
+                throw new IllegalArgumentException("Boolean option '" + name + "' must have value \"true\" or \"false\", not \"" + valueString + "\"");
+            }
+        } else if (optionType == Float.class) {
+            value = Float.parseFloat(valueString);
+        } else if (optionType == Double.class) {
+            value = Double.parseDouble(valueString);
+        } else if (optionType == Integer.class) {
+            value = Integer.valueOf((int) parseLong(valueString));
+        } else if (optionType == Long.class) {
+            value = Long.valueOf(parseLong(valueString));
+        } else if (optionType == String.class) {
+            value = valueString;
+        } else {
+            throw new IllegalArgumentException("Wrong value for option '" + name + "'");
+        }
+        if (setter == null) {
+            desc.getOptionValue().setValue(value);
+        } else {
+            setter.set(desc, value);
+        }
+    }
+
+    private static long parseLong(String v) {
+        String valueString = v.toLowerCase();
+        long scale = 1;
+        if (valueString.endsWith("k")) {
+            scale = 1024L;
+        } else if (valueString.endsWith("m")) {
+            scale = 1024L * 1024L;
+        } else if (valueString.endsWith("g")) {
+            scale = 1024L * 1024L * 1024L;
+        } else if (valueString.endsWith("t")) {
+            scale = 1024L * 1024L * 1024L * 1024L;
+        }
+
+        if (scale != 1) {
+            /* Remove trailing scale character. */
+            valueString = valueString.substring(0, valueString.length() - 1);
+        }
+
+        return Long.parseLong(valueString) * scale;
+    }
+
+    /**
+     * Wraps some given text to one or more lines of a given maximum width.
+     *
+     * @param text text to wrap
+     * @param width maximum width of an output line, exception for words in {@code text} longer than
+     *            this value
+     * @return {@code text} broken into lines
+     */
+    private static List<String> wrap(String text, int width) {
+        List<String> lines = Collections.singletonList(text);
+        if (text.length() > width) {
+            String[] chunks = text.split("\\s+");
+            lines = new ArrayList<>();
+            StringBuilder line = new StringBuilder();
+            for (String chunk : chunks) {
+                if (line.length() + chunk.length() > width) {
+                    lines.add(line.toString());
+                    line.setLength(0);
+                }
+                if (line.length() != 0) {
+                    line.append(' ');
+                }
+                String[] embeddedLines = chunk.split("%n", -2);
+                if (embeddedLines.length == 1) {
+                    line.append(chunk);
+                } else {
+                    for (int i = 0; i < embeddedLines.length; i++) {
+                        line.append(embeddedLines[i]);
+                        if (i < embeddedLines.length - 1) {
+                            lines.add(line.toString());
+                            line.setLength(0);
+                        }
+                    }
+                }
+            }
+            if (line.length() != 0) {
+                lines.add(line.toString());
+            }
+        }
+        return lines;
+    }
+
+    private static void printFlags(Map<String, OptionDescriptor> options, String prefix, PrintStream out, Set<String> explicitlyAssigned) {
+        SortedMap<String, OptionDescriptor> sortedOptions;
+        if (options instanceof SortedMap) {
+            sortedOptions = (SortedMap<String, OptionDescriptor>) options;
+        } else {
+            sortedOptions = new TreeMap<>(options);
+        }
+        out.println("[List of " + prefix + " options]");
+        for (Map.Entry<String, OptionDescriptor> e : sortedOptions.entrySet()) {
+            OptionDescriptor desc = e.getValue();
+            Object value = desc.getOptionValue().getValue();
+            List<String> helpLines = wrap(desc.getHelp(), 70);
+            String name = e.getKey();
+            String assign = explicitlyAssigned.contains(name) ? ":=" : " =";
+            out.printf("%9s %-40s %s %-14s %s%n", desc.getType().getSimpleName(), name, assign, value, helpLines.get(0));
+            for (int i = 1; i < helpLines.size(); i++) {
+                out.printf("%67s %s%n", " ", helpLines.get(i));
+            }
+        }
+    }
+
+    /**
+     * Compute string similarity based on Dice's coefficient.
+     *
+     * Ported from str_similar() in globals.cpp.
+     */
+    static float stringSimiliarity(String str1, String str2) {
+        int hit = 0;
+        for (int i = 0; i < str1.length() - 1; ++i) {
+            for (int j = 0; j < str2.length() - 1; ++j) {
+                if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
+                    ++hit;
+                    break;
+                }
+            }
+        }
+        return 2.0f * hit / (str1.length() + str2.length());
+    }
+
+    private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
+
+    /**
+     * Returns the set of options that fuzzy match a given option name.
+     */
+    private static List<OptionDescriptor> fuzzyMatch(Map<String, OptionDescriptor> options, String optionName) {
+        List<OptionDescriptor> matches = new ArrayList<>();
+        for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
+            float score = stringSimiliarity(e.getKey(), optionName);
+            if (score >= FUZZY_MATCH_THRESHOLD) {
+                matches.add(e.getValue());
+            }
+        }
+        return matches;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.options;
+
+/**
+ * An option that always returns the same {@linkplain #getValue() value}.
+ */
+public class StableOptionValue<T> extends OptionValue<T> {
+
+    /**
+     * Creates a stable option value.
+     */
+    public StableOptionValue(T value) {
+        super(value);
+    }
+
+    /**
+     * Used to assert the invariant for stability. Without using locks, this check is not safe
+     * against races and so it's only an assertion.
+     */
+    private boolean getValueCalled;
+
+    /**
+     * Creates an uninitialized stable option value for a subclass that initializes itself
+     * {@link #defaultValue() lazily}.
+     */
+    public StableOptionValue() {
+    }
+
+    /**
+     * Gets the value of this option.
+     */
+    @Override
+    public final T getValue() {
+        T result = super.getValue();
+        assert initGetValueCalled();
+        return result;
+    }
+
+    private boolean initGetValueCalled() {
+        getValueCalled = true;
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * This must only be called if {@link #getValue()} has never been called.
+     */
+    @Override
+    public final void setValue(Object v) {
+        assert !getValueCalled;
+        super.setValue(v);
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/AddressLoweringPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/AddressLoweringPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.memory.address.AddressNode;
 import com.oracle.graal.nodes.memory.address.OffsetAddressNode;
 import com.oracle.graal.nodes.memory.address.RawAddressNode;
+import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.phases.Phase;
 
 public class AddressLoweringPhase extends Phase {
@@ -59,8 +60,8 @@
             } else {
                 continue;
             }
-
-            node.replaceAndDelete(lowered);
+            node.replaceAtUsages(lowered);
+            GraphUtil.killWithUnusedFloatingInputs(node);
         }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -241,8 +241,7 @@
                 Node newNode = node.graph().findDuplicate(node);
                 if (newNode != null) {
                     assert !(node instanceof FixedNode || newNode instanceof FixedNode);
-                    node.replaceAtUsages(newNode);
-                    node.safeDelete();
+                    node.replaceAtUsagesAndDelete(newNode);
                     METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment();
                     Debug.log("GVN applied and new node is %1s", newNode);
                     return true;
@@ -333,16 +332,9 @@
                     canonical = graph.addOrUniqueWithInputs(canonical);
                 }
                 if (node instanceof FloatingNode) {
-                    if (canonical == null) {
-                        // case 1
-                        node.replaceAtUsages(null);
-                        graph.removeFloating((FloatingNode) node);
-                    } else {
-                        // case 2
-                        assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof AbstractMergeNode) : node + " -> " +
-                                        canonical + " : replacement should be floating or fixed and connected";
-                        graph.replaceFloating((FloatingNode) node, canonical);
-                    }
+                    assert canonical == null || !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof AbstractMergeNode) : node +
+                                    " -> " + canonical + " : replacement should be floating or fixed and connected";
+                    node.replaceAtUsagesAndDelete(canonical);
                 } else {
                     assert node instanceof FixedNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
                     FixedNode fixed = (FixedNode) node;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -383,10 +383,10 @@
         @Override
         public void finished() {
             if (trueConstant.hasNoUsages()) {
-                graph.removeFloating(trueConstant);
+                trueConstant.safeDelete();
             }
             if (falseConstant.hasNoUsages()) {
-                graph.removeFloating(falseConstant);
+                falseConstant.safeDelete();
             }
             super.finished();
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,16 +24,15 @@
 
 import java.util.function.BiConsumer;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeFlood;
 import com.oracle.graal.nodes.AbstractEndNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.Phase;
 
 public class DeadCodeEliminationPhase extends Phase {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -154,10 +154,10 @@
             if (fullSchedule) {
                 SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
                 schedule.apply(graph);
-                ControlFlowGraph cfg = schedule.getCFG();
+                ControlFlowGraph cfg = graph.getLastSchedule().getCFG();
                 cfg.computePostdominators();
-                blockToNodes = b -> schedule.getBlockToNodesMap().get(b);
-                nodeToBlock = n -> schedule.getNodeToBlockMap().get(n);
+                blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b);
+                nodeToBlock = n -> graph.getLastSchedule().getNodeToBlockMap().get(n);
                 startBlock = cfg.getStartBlock();
             } else {
                 ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
@@ -302,9 +302,8 @@
                     if (rewireGuards(infoElement.getGuard(), result.toBoolean(), (guard, checkCastResult) -> {
                         if (checkCastResult) {
                             PiNode piNode = node.graph().unique(new PiNode(node.object(), node.stamp(), guard));
-                            node.replaceAtUsages(piNode);
                             GraphUtil.unlinkFixedNode(node);
-                            node.safeDelete();
+                            node.replaceAtUsagesAndDelete(piNode);
                         } else {
                             DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
                             node.replaceAtPredecessor(deopt);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -54,6 +54,7 @@
  * This Phase processes the graph in post order, assigning the {@link FrameState} from the last
  * {@link StateSplit} node to {@link DeoptimizingNode DeoptimizingNodes}.
  */
+@SuppressWarnings("unused")
 public class FrameStateAssignmentPhase extends Phase {
 
     private static class FrameStateAssignmentClosure extends NodeIteratorClosure<FrameState> {
@@ -116,7 +117,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        assert !graph.getGuardsStage().allowsFloatingGuards() && checkFixedDeopts(graph);
+        assert !graph.getGuardsStage().allowsFloatingGuards() && !hasFloatingDeopts(graph);
         if (graph.getGuardsStage().areFrameStatesAtSideEffects()) {
             ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null);
             graph.setGuardsStage(GuardsStage.AFTER_FSA);
@@ -124,14 +125,16 @@
         }
     }
 
-    private static boolean checkFixedDeopts(StructuredGraph graph) {
-        NodePredicate isFloatingNode = GraphUtil.isFloatingNode();
-        for (Node n : graph.getNodes().filterInterface(DeoptimizingNode.class)) {
-            if (((DeoptimizingNode) n).canDeoptimize() && isFloatingNode.apply(n)) {
-                return false;
+    private static boolean hasFloatingDeopts(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof DeoptimizingNode && GraphUtil.isFloatingNode(n)) {
+                DeoptimizingNode deoptimizingNode = (DeoptimizingNode) n;
+                if (deoptimizingNode.canDeoptimize()) {
+                    return true;
+                }
             }
         }
-        return true;
+        return false;
     }
 
     private static FrameState singleFrameState(List<FrameState> states) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -47,6 +47,7 @@
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.IsNullNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -259,8 +260,9 @@
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
         if (graph.getGuardsStage().allowsFloatingGuards()) {
-            SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
-            schedule.apply(graph);
+            SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+            schedulePhase.apply(graph);
+            ScheduleResult schedule = graph.getLastSchedule();
 
             for (Block block : schedule.getCFG().getBlocks()) {
                 processBlock(block, schedule, context != null ? context.getTarget().implicitNullCheckLimit : 0);
@@ -276,7 +278,7 @@
         return true;
     }
 
-    private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) {
+    private static void processBlock(Block block, ScheduleResult schedule, int implicitNullCheckLimit) {
         if (OptImplicitNullChecks.getValue() && implicitNullCheckLimit > 0) {
             new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(block, schedule);
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -58,6 +58,7 @@
 import com.oracle.graal.nodes.GuardNode;
 import com.oracle.graal.nodes.LogicNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -272,7 +273,8 @@
 
         private final PhaseContext context;
         private final LoweringMode mode;
-        private final SchedulePhase schedule;
+        private ScheduleResult schedule;
+        private final SchedulePhase schedulePhase;
 
         private Round(PhaseContext context, LoweringMode mode) {
             this.context = context;
@@ -285,7 +287,7 @@
              */
             boolean immutableSchedule = mode == LoweringMode.VERIFY_LOWERING;
 
-            this.schedule = new SchedulePhase(immutableSchedule);
+            this.schedulePhase = new SchedulePhase(immutableSchedule);
         }
 
         @Override
@@ -302,7 +304,8 @@
 
         @Override
         public void run(StructuredGraph graph) {
-            schedule.apply(graph, false);
+            schedulePhase.apply(graph, false);
+            schedule = graph.getLastSchedule();
             schedule.getCFG().computePostdominators();
             Block startBlock = schedule.getCFG().getStartBlock();
             ProcessFrame rootFrame = new ProcessFrame(startBlock, graph.createNodeBitMap(), startBlock.getBeginNode(), null);
@@ -457,7 +460,7 @@
      *     if (alwaysReachedBlock != null &amp;&amp; alwaysReachedBlock.getDominator() == block) {
      *         processBlock(alwaysReachedBlock);
      *     }
-     *
+     * 
      *     // Now go for the other dominators.
      *     for (Block dominated : block.getDominated()) {
      *         if (dominated != alwaysReachedBlock) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -42,6 +42,7 @@
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.SafepointNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.UnwindNode;
 import com.oracle.graal.nodes.VirtualState;
 import com.oracle.graal.nodes.calc.BinaryNode;
@@ -97,7 +98,7 @@
         for (Loop<Block> loop : cfg.getLoops()) {
             double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).probability();
             if (loopProbability > (1D / Integer.MAX_VALUE)) {
-                addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), schedule, cfg);
+                addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), graph.getLastSchedule(), cfg);
             }
         }
         // don't put the counter increase directly after the start (problems with OSR)
@@ -105,7 +106,7 @@
         while (current.next() instanceof FixedWithNextNode) {
             current = (FixedWithNextNode) current.next();
         }
-        addSectionCounters(current, cfg.getBlocks(), cfg.getLoops(), schedule, cfg);
+        addSectionCounters(current, cfg.getBlocks(), cfg.getLoops(), graph.getLastSchedule(), cfg);
 
         if (WITH_INVOKES) {
             for (Node node : graph.getNodes()) {
@@ -118,7 +119,7 @@
         }
     }
 
-    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, SchedulePhase schedule, ControlFlowGraph cfg) {
+    private static void addSectionCounters(FixedWithNextNode start, Collection<Block> sectionBlocks, Collection<Loop<Block>> childLoops, ScheduleResult schedule, ControlFlowGraph cfg) {
         HashSet<Block> blocks = new HashSet<>(sectionBlocks);
         for (Loop<?> loop : childLoops) {
             blocks.removeAll(loop.getBlocks());
@@ -138,7 +139,7 @@
         }
     }
 
-    private static double getSectionWeight(SchedulePhase schedule, Collection<Block> blocks) {
+    private static double getSectionWeight(ScheduleResult schedule, Collection<Block> blocks) {
         double count = 0;
         for (Block block : blocks) {
             double blockProbability = block.probability();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -34,7 +34,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (ProxyNode vpn : graph.getNodes(ProxyNode.TYPE)) {
-            graph.replaceFloating(vpn, vpn.value());
+            vpn.replaceAtUsagesAndDelete(vpn.value());
         }
         for (LoopExitNode exit : graph.getNodes(LoopExitNode.TYPE)) {
             FrameState stateAfter = exit.stateAfter();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,12 +24,11 @@
 
 import java.util.Map;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.common.AbstractInliningPhase;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Tue Jan 05 16:42:05 2016 -0800
@@ -121,7 +121,7 @@
             // 1234
             TTY.print("     ");        // print compilation number
             // % s ! b n
-            TTY.print("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
+            TTY.printf("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
             TTY.print("     ");        // more indent
             TTY.print("    ");         // initial inlining indent
             for (int i = 0; i < inliningDepth; i++) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Tue Jan 05 16:42:05 2016 -0800
@@ -164,7 +164,7 @@
                     Constant constant = arg.asConstant();
                     parameterUsages = trackParameterUsages(param, parameterUsages);
                     // collect param usages before replacing the param
-                    graph.replaceFloating(param, ConstantNode.forConstant(arg.stamp(), constant, context.getMetaAccess(), graph));
+                    param.replaceAtUsagesAndDelete(ConstantNode.forConstant(arg.stamp(), constant, context.getMetaAccess(), graph));
                     // param-node gone, leaving a gap in the sequence given by param.index()
                 } else {
                     Stamp impro = improvedStamp(arg, param);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,12 +27,12 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.FixedWithNextNode;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 /**
  * Iterates over a list of nodes, which usually comes from
- * {@link SchedulePhase#getBlockToNodesMap()}.
+ * {@link ScheduleResult#getBlockToNodesMap()}.
  *
  * While iterating, it is possible to {@link #insert(FixedNode, FixedWithNextNode) insert} and
  * {@link #replaceCurrent(FixedWithNextNode) replace} nodes.
@@ -43,11 +43,11 @@
     private FixedWithNextNode reconnect;
     private ListIterator<Node> iterator;
 
-    public void processNodes(Block block, SchedulePhase shedule) {
+    public void processNodes(Block block, ScheduleResult schedule) {
         lastFixed = block.getBeginNode();
         assert lastFixed != null;
         reconnect = null;
-        iterator = shedule.nodesFor(block).listIterator();
+        iterator = schedule.nodesFor(block).listIterator();
 
         while (iterator.hasNext()) {
             Node node = iterator.next();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/SinglePassNodeIterator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,7 +25,6 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Deque;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -226,17 +225,18 @@
      * </p>
      */
     private void queueSuccessors(FixedNode x) {
-        Iterator<Node> iter = x.successors().nonNull().iterator();
-        if (iter.hasNext()) {
-            AbstractBeginNode begin = (AbstractBeginNode) iter.next();
-            // the current state isn't cloned for the first successor
-            // conceptually, the state is handed over to it
-            nodeQueue.addFirst(new PathStart<>(begin, state));
-        }
-        while (iter.hasNext()) {
-            AbstractBeginNode begin = (AbstractBeginNode) iter.next();
-            // for all other successors it is cloned
-            nodeQueue.addFirst(new PathStart<>(begin, state.clone()));
+        T startState = state;
+        T curState = startState;
+        for (Node succ : x.successors()) {
+            if (succ != null) {
+                if (curState == null) {
+                    // the current state isn't cloned for the first successor
+                    // conceptually, the state is handed over to it
+                    curState = startState.clone();
+                }
+                AbstractBeginNode begin = (AbstractBeginNode) succ;
+                nodeQueue.addFirst(new PathStart<>(begin, curState));
+            }
         }
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -23,7 +23,6 @@
 package com.oracle.graal.phases.schedule;
 
 import static com.oracle.graal.compiler.common.GraalOptions.OptScheduleOutOfLoops;
-import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.dominates;
 import static com.oracle.graal.compiler.common.cfg.AbstractControlFlowGraph.strictlyDominates;
 
 import java.util.ArrayList;
@@ -60,6 +59,7 @@
 import com.oracle.graal.nodes.StartNode;
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.VirtualState;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
@@ -75,45 +75,14 @@
 
 public final class SchedulePhase extends Phase {
 
-    /**
-     * Error thrown when a graph cannot be scheduled.
-     */
-    public static class SchedulingError extends Error {
-
-        private static final long serialVersionUID = 1621001069476473145L;
-
-        public SchedulingError() {
-            super();
-        }
-
-        /**
-         * This constructor creates a {@link SchedulingError} with a message assembled via
-         * {@link String#format(String, Object...)}.
-         *
-         * @param format a {@linkplain Formatter format} string
-         * @param args parameters to {@link String#format(String, Object...)}
-         */
-        public SchedulingError(String format, Object... args) {
-            super(String.format(format, args));
-        }
-
-    }
-
     public static enum SchedulingStrategy {
         EARLIEST,
         LATEST,
-        LATEST_OUT_OF_LOOPS
+        LATEST_OUT_OF_LOOPS,
+        FINAL_SCHEDULE
     }
 
-    private ControlFlowGraph cfg;
-
-    /**
-     * Map from blocks to the nodes in each block.
-     */
-    private BlockMap<List<Node>> blockToNodesMap;
-    private BlockMap<LocationSet> blockToKillSet;
     private final SchedulingStrategy selectedStrategy;
-    private NodeMap<Block> nodeToBlockMap;
 
     private final boolean immutableGraph;
 
@@ -129,7 +98,7 @@
         this(strategy, false);
     }
 
-    public SchedulePhase(SchedulingStrategy strategy, boolean immutableGraph) {
+    private SchedulePhase(SchedulingStrategy strategy, boolean immutableGraph) {
         this.selectedStrategy = strategy;
         this.immutableGraph = immutableGraph;
     }
@@ -152,6 +121,22 @@
     @SuppressWarnings("try")
     protected void run(StructuredGraph graph) {
         try (NodeEventScope scope = verifyImmutableGraph(graph)) {
+            Instance inst = new Instance();
+            inst.run(graph, selectedStrategy, immutableGraph);
+        }
+    }
+
+    public static class Instance {
+
+        /**
+         * Map from blocks to the nodes in each block.
+         */
+        protected ControlFlowGraph cfg;
+        protected BlockMap<List<Node>> blockToNodesMap;
+        protected NodeMap<Block> nodeToBlockMap;
+
+        @SuppressWarnings("try")
+        public void run(StructuredGraph graph, SchedulingStrategy selectedStrategy, boolean immutableGraph) {
             // assert GraphOrder.assertNonCyclicGraph(graph);
             cfg = ControlFlowGraph.compute(graph, true, true, true, false);
 
@@ -160,69 +145,67 @@
                 this.nodeToBlockMap = graph.createNodeMap();
                 this.blockToNodesMap = new BlockMap<>(cfg);
                 NodeBitMap visited = graph.createNodeBitMap();
-                scheduleEarliestIterative(blockToNodesMap, nodeToBlockMap, visited, graph, null);
-                return;
+                scheduleEarliestIterative(blockToNodesMap, nodeToBlockMap, visited, graph, null, immutableGraph);
             } else {
-                boolean isOutOfLoops = selectedStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS;
-                if (selectedStrategy == SchedulingStrategy.LATEST || isOutOfLoops) {
-                    NodeMap<Block> currentNodeMap = graph.createNodeMap();
-                    BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
-                    NodeBitMap visited = graph.createNodeBitMap();
-                    NodeBitMap unreachableNodes = immutableGraph ? graph.createNodeBitMap() : null;
+                NodeMap<Block> currentNodeMap = graph.createNodeMap();
+                BlockMap<List<Node>> earliestBlockToNodesMap = new BlockMap<>(cfg);
+                NodeBitMap visited = graph.createNodeBitMap();
+                NodeBitMap unreachableNodes = immutableGraph ? graph.createNodeBitMap() : null;
 
-                    // Assign early so we are getting a context in case of an exception.
-                    this.blockToNodesMap = earliestBlockToNodesMap;
-                    this.nodeToBlockMap = currentNodeMap;
+                // Assign early so we are getting a context in case of an exception.
+                this.blockToNodesMap = earliestBlockToNodesMap;
+                this.nodeToBlockMap = currentNodeMap;
+
+                scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, unreachableNodes, immutableGraph);
+                BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
 
-                    scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, unreachableNodes);
-                    BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
-
-                    for (Block b : cfg.getBlocks()) {
-                        latestBlockToNodesMap.put(b, new ArrayList<Node>());
-                    }
+                for (Block b : cfg.getBlocks()) {
+                    latestBlockToNodesMap.put(b, new ArrayList<Node>());
+                }
 
-                    BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, unreachableNodes);
-                    sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+                BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, unreachableNodes,
+                                immutableGraph);
+                sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
 
-                    assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
-                    assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
+                assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
+                assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
 
-                    this.blockToNodesMap = latestBlockToNodesMap;
-                    this.nodeToBlockMap = currentNodeMap;
+                this.blockToNodesMap = latestBlockToNodesMap;
+                this.nodeToBlockMap = currentNodeMap;
 
-                    cfg.setNodeToBlock(currentNodeMap);
-                }
+                cfg.setNodeToBlock(currentNodeMap);
             }
+
+            graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap));
         }
-    }
 
-    @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
-    private BlockMap<ArrayList<FloatingReadNode>> calcLatestBlocks(boolean isOutOfLoops, NodeMap<Block> currentNodeMap, BlockMap<List<Node>> earliestBlockToNodesMap, NodeBitMap visited,
-                    BlockMap<List<Node>> latestBlockToNodesMap, NodeBitMap unreachableNodes) {
-        BlockMap<ArrayList<FloatingReadNode>> watchListMap = null;
-        for (Block b : cfg.postOrder()) {
-            List<Node> blockToNodes = earliestBlockToNodesMap.get(b);
-            LocationSet killed = null;
-            int previousIndex = blockToNodes.size();
-            for (int i = blockToNodes.size() - 1; i >= 0; --i) {
-                Node currentNode = blockToNodes.get(i);
-                assert currentNodeMap.get(currentNode) == b;
-                assert !(currentNode instanceof PhiNode) && !(currentNode instanceof ProxyNode);
-                assert visited.isMarked(currentNode);
-                if (currentNode instanceof FixedNode) {
-                    // For these nodes, the earliest is at the same time the latest block.
-                } else {
-                    Block currentBlock = b;
-                    assert currentBlock != null;
+        @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE", justification = "false positive found by findbugs")
+        private BlockMap<ArrayList<FloatingReadNode>> calcLatestBlocks(SchedulingStrategy strategy, NodeMap<Block> currentNodeMap, BlockMap<List<Node>> earliestBlockToNodesMap, NodeBitMap visited,
+                        BlockMap<List<Node>> latestBlockToNodesMap, NodeBitMap unreachableNodes, boolean immutableGraph) {
+            BlockMap<ArrayList<FloatingReadNode>> watchListMap = new BlockMap<>(cfg);
+            for (Block currentBlock : cfg.postOrder()) {
+                List<Node> blockToNodes = earliestBlockToNodesMap.get(currentBlock);
+                LocationSet killed = null;
+                int previousIndex = blockToNodes.size();
+                for (int i = blockToNodes.size() - 1; i >= 0; --i) {
+                    Node currentNode = blockToNodes.get(i);
+                    assert currentNodeMap.get(currentNode) == currentBlock;
+                    assert !(currentNode instanceof PhiNode) && !(currentNode instanceof ProxyNode);
+                    assert visited.isMarked(currentNode);
+                    if (currentNode instanceof FixedNode) {
+                        // For these nodes, the earliest is at the same time the latest block.
+                    } else {
+                        Block latestBlock = null;
 
-                    Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap, unreachableNodes);
-                    assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock);
-                    if (latestBlock != currentBlock) {
+                        LocationIdentity constrainingLocation = null;
                         if (currentNode instanceof FloatingReadNode) {
-
+                            // We are scheduling a floating read node => check memory
+                            // anti-dependencies.
                             FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode;
                             LocationIdentity location = floatingReadNode.getLocationIdentity();
                             if (location.isMutable()) {
+                                // Location can be killed.
+                                constrainingLocation = location;
                                 if (currentBlock.canKill(location)) {
                                     if (killed == null) {
                                         killed = new LocationSet();
@@ -230,651 +213,648 @@
                                     fillKillSet(killed, blockToNodes.subList(i + 1, previousIndex));
                                     previousIndex = i;
                                     if (killed.contains(location)) {
+                                        // Earliest block kills location => we need to stay within
+                                        // earliest block.
                                         latestBlock = currentBlock;
                                     }
                                 }
-
-                                if (latestBlock != currentBlock) {
-                                    // We are not constraint within currentBlock. Check if
-                                    // we are contraint while walking down the dominator
-                                    // line.
-                                    Block newLatestBlock = adjustLatestForRead(floatingReadNode, currentBlock, latestBlock, location);
-                                    assert dominates(newLatestBlock, latestBlock);
-                                    assert dominates(currentBlock, newLatestBlock);
-                                    latestBlock = newLatestBlock;
-
-                                    if (newLatestBlock != currentBlock && latestBlock.canKill(location)) {
-                                        if (watchListMap == null) {
-                                            watchListMap = new BlockMap<>(cfg);
-                                        }
-                                        if (watchListMap.get(latestBlock) == null) {
-                                            watchListMap.put(latestBlock, new ArrayList<>());
-                                        }
-                                        watchListMap.get(latestBlock).add(floatingReadNode);
-                                    }
-                                }
                             }
                         }
-                        currentNodeMap.set(currentNode, latestBlock);
-                        currentBlock = latestBlock;
+
+                        if (latestBlock == null) {
+                            // We are not constraint within earliest block => calculate optimized
+                            // schedule.
+                            calcLatestBlock(currentBlock, strategy, currentNode, currentNodeMap, unreachableNodes, constrainingLocation, watchListMap, latestBlockToNodesMap, visited, immutableGraph);
+                        } else {
+                            selectLatestBlock(currentNode, currentBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap);
+                        }
                     }
-                    latestBlockToNodesMap.get(currentBlock).add(currentNode);
-                }
-            }
-        }
-        return watchListMap;
-    }
-
-    private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) {
-        assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format(
-                        "%s %s (%s) %s (%s)", currentNode, earliestBlock, earliestBlock.getBeginNode(), latestBlock, latestBlock.getBeginNode());
-        return true;
-    }
-
-    private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
-        for (Block b : cfg.getBlocks()) {
-            List<Node> nodes = blockToNodesMap.get(b);
-            for (Node n : nodes) {
-                assert n.isAlive();
-                assert nodeMap.get(n) == b;
-                StructuredGraph g = (StructuredGraph) n.graph();
-                if (g.hasLoops() && g.getGuardsStage() == GuardsStage.AFTER_FSA && n instanceof DeoptimizeNode) {
-                    assert b.getLoopDepth() == 0 : n;
                 }
             }
-        }
-        return true;
-    }
-
-    private static Block adjustLatestForRead(FloatingReadNode floatingReadNode, Block earliestBlock, Block latestBlock, LocationIdentity location) {
-        assert strictlyDominates(earliestBlock, latestBlock);
-        Block current = latestBlock.getDominator();
-
-        // Collect dominator chain that needs checking.
-        List<Block> dominatorChain = new ArrayList<>();
-        dominatorChain.add(latestBlock);
-        while (current != earliestBlock) {
-            // Current is an intermediate dominator between earliestBlock and latestBlock.
-            assert strictlyDominates(earliestBlock, current) && strictlyDominates(current, latestBlock);
-            if (current.canKill(location)) {
-                dominatorChain.clear();
-            }
-            dominatorChain.add(current);
-            current = current.getDominator();
-            assert current != null : floatingReadNode;
+            return watchListMap;
         }
 
-        // The first element of dominatorChain now contains the latest possible block.
-        assert dominatorChain.size() >= 1;
-        assert dominatorChain.get(dominatorChain.size() - 1).getDominator() == earliestBlock;
+        protected static void selectLatestBlock(Node currentNode, Block currentBlock, Block latestBlock, NodeMap<Block> currentNodeMap, BlockMap<ArrayList<FloatingReadNode>> watchListMap,
+                        LocationIdentity constrainingLocation, BlockMap<List<Node>> latestBlockToNodesMap) {
 
-        Block lastBlock = earliestBlock;
-        for (int i = dominatorChain.size() - 1; i >= 0; --i) {
-            Block currentBlock = dominatorChain.get(i);
-            if (currentBlock.getLoopDepth() > lastBlock.getLoopDepth()) {
-                // We are entering a loop boundary. The new loops must not kill the location for the
-                // crossing to be safe.
-                if (currentBlock.getLoop() != null && ((HIRLoop) currentBlock.getLoop()).canKill(location)) {
-                    break;
+            assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock);
+            if (currentBlock != latestBlock) {
+                currentNodeMap.setAndGrow(currentNode, latestBlock);
+
+                if (constrainingLocation != null && latestBlock.canKill(constrainingLocation)) {
+                    if (watchListMap.get(latestBlock) == null) {
+                        watchListMap.put(latestBlock, new ArrayList<>());
+                    }
+                    watchListMap.get(latestBlock).add((FloatingReadNode) currentNode);
                 }
             }
 
-            if (currentBlock.canKillBetweenThisAndDominator(location)) {
-                break;
+            latestBlockToNodesMap.get(latestBlock).add(currentNode);
+        }
+
+        private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) {
+            assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format(
+                            "%s %s (%s) %s (%s)", currentNode, earliestBlock, earliestBlock.getBeginNode(), latestBlock, latestBlock.getBeginNode());
+            return true;
+        }
+
+        private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
+            for (Block b : cfg.getBlocks()) {
+                List<Node> nodes = blockToNodesMap.get(b);
+                for (Node n : nodes) {
+                    assert n.isAlive();
+                    assert nodeMap.get(n) == b;
+                    StructuredGraph g = (StructuredGraph) n.graph();
+                    if (g.hasLoops() && g.getGuardsStage() == GuardsStage.AFTER_FSA && n instanceof DeoptimizeNode) {
+                        assert b.getLoopDepth() == 0 : n;
+                    }
+                }
             }
-            lastBlock = currentBlock;
+            return true;
         }
 
-        return lastBlock;
-    }
+        public static Block checkKillsBetween(Block earliestBlock, Block latestBlock, LocationIdentity location) {
+            assert strictlyDominates(earliestBlock, latestBlock);
+            Block current = latestBlock.getDominator();
+
+            // Collect dominator chain that needs checking.
+            List<Block> dominatorChain = new ArrayList<>();
+            dominatorChain.add(latestBlock);
+            while (current != earliestBlock) {
+                // Current is an intermediate dominator between earliestBlock and latestBlock.
+                assert strictlyDominates(earliestBlock, current) && strictlyDominates(current, latestBlock);
+                if (current.canKill(location)) {
+                    dominatorChain.clear();
+                }
+                dominatorChain.add(current);
+                current = current.getDominator();
+            }
+
+            // The first element of dominatorChain now contains the latest possible block.
+            assert dominatorChain.size() >= 1;
+            assert dominatorChain.get(dominatorChain.size() - 1).getDominator() == earliestBlock;
 
-    private static void fillKillSet(LocationSet killed, List<Node> subList) {
-        if (!killed.isAny()) {
-            for (Node n : subList) {
-                // Check if this node kills a node in the watch list.
-                if (n instanceof MemoryCheckpoint.Single) {
-                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
-                    killed.add(identity);
-                    if (killed.isAny()) {
-                        return;
+            Block lastBlock = earliestBlock;
+            for (int i = dominatorChain.size() - 1; i >= 0; --i) {
+                Block currentBlock = dominatorChain.get(i);
+                if (currentBlock.getLoopDepth() > lastBlock.getLoopDepth()) {
+                    // We are entering a loop boundary. The new loops must not kill the location for
+                    // the crossing to be safe.
+                    if (currentBlock.getLoop() != null && ((HIRLoop) currentBlock.getLoop()).canKill(location)) {
+                        break;
                     }
-                } else if (n instanceof MemoryCheckpoint.Multi) {
-                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                }
+
+                if (currentBlock.canKillBetweenThisAndDominator(location)) {
+                    break;
+                }
+                lastBlock = currentBlock;
+            }
+
+            return lastBlock;
+        }
+
+        private static void fillKillSet(LocationSet killed, List<Node> subList) {
+            if (!killed.isAny()) {
+                for (Node n : subList) {
+                    // Check if this node kills a node in the watch list.
+                    if (n instanceof MemoryCheckpoint.Single) {
+                        LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
                         killed.add(identity);
                         if (killed.isAny()) {
                             return;
                         }
+                    } else if (n instanceof MemoryCheckpoint.Multi) {
+                        for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                            killed.add(identity);
+                            if (killed.isAny()) {
+                                return;
+                            }
+                        }
                     }
                 }
             }
         }
-    }
 
-    private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> currentNodeMap,
-                    BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap visited) {
-        for (Block b : cfg.getBlocks()) {
-            sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+        private static void sortNodesLatestWithinBlock(ControlFlowGraph cfg, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> currentNodeMap,
+                        BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap visited) {
+            for (Block b : cfg.getBlocks()) {
+                sortNodesLatestWithinBlock(b, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
+            }
         }
-    }
 
-    private static void sortNodesLatestWithinBlock(Block b, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> nodeMap,
-                    BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap unprocessed) {
-        List<Node> earliestSorting = earliestBlockToNodesMap.get(b);
-        ArrayList<Node> result = new ArrayList<>(earliestSorting.size());
-        ArrayList<FloatingReadNode> watchList = null;
-        if (watchListMap != null) {
-            watchList = watchListMap.get(b);
-            assert watchList == null || !b.getKillLocations().isEmpty();
-        }
-        AbstractBeginNode beginNode = b.getBeginNode();
-        if (beginNode instanceof LoopExitNode) {
-            LoopExitNode loopExitNode = (LoopExitNode) beginNode;
-            for (ProxyNode proxy : loopExitNode.proxies()) {
-                unprocessed.clear(proxy);
-                ValueNode value = proxy.value();
-                if (value != null && nodeMap.get(value) == b) {
-                    sortIntoList(value, b, result, nodeMap, unprocessed, null);
+        private static void sortNodesLatestWithinBlock(Block b, BlockMap<List<Node>> earliestBlockToNodesMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeMap<Block> nodeMap,
+                        BlockMap<ArrayList<FloatingReadNode>> watchListMap, NodeBitMap unprocessed) {
+            List<Node> earliestSorting = earliestBlockToNodesMap.get(b);
+            ArrayList<Node> result = new ArrayList<>(earliestSorting.size());
+            ArrayList<FloatingReadNode> watchList = null;
+            if (watchListMap != null) {
+                watchList = watchListMap.get(b);
+                assert watchList == null || !b.getKillLocations().isEmpty();
+            }
+            AbstractBeginNode beginNode = b.getBeginNode();
+            if (beginNode instanceof LoopExitNode) {
+                LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+                for (ProxyNode proxy : loopExitNode.proxies()) {
+                    unprocessed.clear(proxy);
+                    ValueNode value = proxy.value();
+                    if (value != null && nodeMap.get(value) == b) {
+                        sortIntoList(value, b, result, nodeMap, unprocessed, null);
+                    }
                 }
             }
-        }
-        FixedNode endNode = b.getEndNode();
-        FixedNode fixedEndNode = null;
-        if (isFixedEnd(endNode)) {
-            // Only if the end node is either a control split or an end node, we need to force it to
-            // be the last node in the schedule.
-            fixedEndNode = endNode;
+            FixedNode endNode = b.getEndNode();
+            FixedNode fixedEndNode = null;
+            if (isFixedEnd(endNode)) {
+                // Only if the end node is either a control split or an end node, we need to force
+                // it to be the last node in the schedule.
+                fixedEndNode = endNode;
+            }
+            for (Node n : earliestSorting) {
+                if (n != fixedEndNode) {
+                    if (n instanceof FixedNode) {
+                        assert nodeMap.get(n) == b;
+                        checkWatchList(b, nodeMap, unprocessed, result, watchList, n);
+                        sortIntoList(n, b, result, nodeMap, unprocessed, null);
+                    } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) {
+                        FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                        LocationIdentity location = floatingReadNode.getLocationIdentity();
+                        if (b.canKill(location)) {
+                            // This read can be killed in this block, add to watch list.
+                            if (watchList == null) {
+                                watchList = new ArrayList<>();
+                            }
+                            watchList.add(floatingReadNode);
+                        }
+                    }
+                }
+            }
+
+            for (Node n : latestBlockToNodesMap.get(b)) {
+                assert nodeMap.get(n) == b : n;
+                assert !(n instanceof FixedNode);
+                if (unprocessed.isMarked(n)) {
+                    sortIntoList(n, b, result, nodeMap, unprocessed, fixedEndNode);
+                }
+            }
+
+            if (endNode != null && unprocessed.isMarked(endNode)) {
+                sortIntoList(endNode, b, result, nodeMap, unprocessed, null);
+            }
+
+            latestBlockToNodesMap.put(b, result);
         }
-        for (Node n : earliestSorting) {
-            if (n != fixedEndNode) {
-                if (n instanceof FixedNode) {
-                    assert nodeMap.get(n) == b;
-                    checkWatchList(b, nodeMap, unprocessed, result, watchList, n);
-                    sortIntoList(n, b, result, nodeMap, unprocessed, null);
-                } else if (nodeMap.get(n) == b && n instanceof FloatingReadNode) {
-                    FloatingReadNode floatingReadNode = (FloatingReadNode) n;
-                    LocationIdentity location = floatingReadNode.getLocationIdentity();
-                    if (b.canKill(location)) {
-                        // This read can be killed in this block, add to watch list.
-                        if (watchList == null) {
-                            watchList = new ArrayList<>();
-                        }
-                        watchList.add(floatingReadNode);
+
+        private static void checkWatchList(Block b, NodeMap<Block> nodeMap, NodeBitMap unprocessed, ArrayList<Node> result, ArrayList<FloatingReadNode> watchList, Node n) {
+            if (watchList != null && !watchList.isEmpty()) {
+                // Check if this node kills a node in the watch list.
+                if (n instanceof MemoryCheckpoint.Single) {
+                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                    checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                        checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
                     }
                 }
             }
         }
 
-        for (Node n : latestBlockToNodesMap.get(b)) {
-            assert nodeMap.get(n) == b;
-            assert !(n instanceof FixedNode);
-            if (unprocessed.isMarked(n)) {
-                sortIntoList(n, b, result, nodeMap, unprocessed, fixedEndNode);
-            }
-        }
-
-        if (endNode != null && unprocessed.isMarked(endNode)) {
-            sortIntoList(endNode, b, result, nodeMap, unprocessed, null);
-        }
-
-        latestBlockToNodesMap.put(b, result);
-    }
-
-    private static void checkWatchList(Block b, NodeMap<Block> nodeMap, NodeBitMap unprocessed, ArrayList<Node> result, ArrayList<FloatingReadNode> watchList, Node n) {
-        if (watchList != null && !watchList.isEmpty()) {
-            // Check if this node kills a node in the watch list.
-            if (n instanceof MemoryCheckpoint.Single) {
-                LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
-                checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
-            } else if (n instanceof MemoryCheckpoint.Multi) {
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
-                    checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
-                }
-            }
-        }
-    }
-
-    private static void checkWatchList(ArrayList<FloatingReadNode> watchList, LocationIdentity identity, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed) {
-        assert identity.isMutable();
-        if (identity.isAny()) {
-            for (FloatingReadNode r : watchList) {
-                if (unprocessed.isMarked(r)) {
-                    sortIntoList(r, b, result, nodeMap, unprocessed, null);
-                }
-            }
-            watchList.clear();
-        } else {
-            int index = 0;
-            while (index < watchList.size()) {
-                FloatingReadNode r = watchList.get(index);
-                LocationIdentity locationIdentity = r.getLocationIdentity();
-                assert locationIdentity.isMutable();
-                if (unprocessed.isMarked(r)) {
-                    if (identity.overlaps(locationIdentity)) {
+        private static void checkWatchList(ArrayList<FloatingReadNode> watchList, LocationIdentity identity, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed) {
+            assert identity.isMutable();
+            if (identity.isAny()) {
+                for (FloatingReadNode r : watchList) {
+                    if (unprocessed.isMarked(r)) {
                         sortIntoList(r, b, result, nodeMap, unprocessed, null);
-                    } else {
-                        ++index;
-                        continue;
                     }
                 }
-                int lastIndex = watchList.size() - 1;
-                watchList.set(index, watchList.get(lastIndex));
-                watchList.remove(lastIndex);
-            }
-        }
-    }
-
-    private static void sortIntoList(Node n, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed, Node excludeNode) {
-        assert unprocessed.isMarked(n) : n;
-        unprocessed.clear(n);
-
-        assert nodeMap.get(n) == b;
-
-        if (n instanceof PhiNode) {
-            return;
-        }
-
-        for (Node input : n.inputs()) {
-            if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) {
-                sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode);
-            }
-        }
-
-        if (n instanceof ProxyNode) {
-            // Skip proxy nodes.
-        } else {
-            result.add(n);
-        }
-
-    }
-
-    private Block calcLatestBlock(Block earliestBlock, boolean scheduleOutOfLoops, Node currentNode, NodeMap<Block> currentNodeMap, NodeBitMap unreachableNodes) {
-        Block block = null;
-        assert currentNode.hasUsages();
-        for (Node usage : currentNode.usages()) {
-            if (unreachableNodes != null && unreachableNodes.contains(usage)) {
-                /*
-                 * Normally, dead nodes are deleted by the scheduler before we reach this point.
-                 * Only when the scheduler is asked to not modify a graph, we can see dead nodes
-                 * here.
-                 */
-                assert immutableGraph;
-                continue;
-            }
-            block = calcBlockForUsage(currentNode, usage, block, currentNodeMap);
-            assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
-            if (scheduleOutOfLoops) {
-                while (block.getLoopDepth() > earliestBlock.getLoopDepth() && block != earliestBlock.getDominator()) {
-                    block = block.getDominator();
-                    assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
-                }
-            }
-        }
-        assert block != null : currentNode;
-        return block;
-    }
-
-    private static Block calcBlockForUsage(Node node, Node usage, Block startCurrentBlock, NodeMap<Block> currentNodeMap) {
-        assert !(node instanceof PhiNode);
-        Block currentBlock = startCurrentBlock;
-        if (usage instanceof PhiNode) {
-            // An input to a PhiNode is used at the end of the predecessor block that corresponds to
-            // the PhiNode input. One PhiNode can use an input multiple times.
-            PhiNode phi = (PhiNode) usage;
-            AbstractMergeNode merge = phi.merge();
-            Block mergeBlock = currentNodeMap.get(merge);
-            for (int i = 0; i < phi.valueCount(); ++i) {
-                if (phi.valueAt(i) == node) {
-                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i));
-                }
-            }
-        } else if (usage instanceof AbstractBeginNode) {
-            AbstractBeginNode abstractBeginNode = (AbstractBeginNode) usage;
-            if (abstractBeginNode instanceof StartNode) {
-                currentBlock = currentNodeMap.get(abstractBeginNode);
+                watchList.clear();
             } else {
-                currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(abstractBeginNode).getDominator());
-            }
-        } else {
-            // All other types of usages: Put the input into the same block as the usage.
-            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(usage));
-        }
-        return currentBlock;
-    }
-
-    private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, NodeBitMap unreachableNodes) {
-
-        BitSet floatingReads = new BitSet(cfg.getBlocks().size());
-
-        // Add begin nodes as the first entry and set the block for phi nodes.
-        for (Block b : cfg.getBlocks()) {
-            AbstractBeginNode beginNode = b.getBeginNode();
-            ArrayList<Node> nodes = new ArrayList<>();
-            nodeToBlock.set(beginNode, b);
-            nodes.add(beginNode);
-            blockToNodes.put(b, nodes);
-
-            if (beginNode instanceof AbstractMergeNode) {
-                AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
-                for (PhiNode phi : mergeNode.phis()) {
-                    nodeToBlock.set(phi, b);
-                }
-            } else if (beginNode instanceof LoopExitNode) {
-                LoopExitNode loopExitNode = (LoopExitNode) beginNode;
-                for (ProxyNode proxy : loopExitNode.proxies()) {
-                    nodeToBlock.set(proxy, b);
+                int index = 0;
+                while (index < watchList.size()) {
+                    FloatingReadNode r = watchList.get(index);
+                    LocationIdentity locationIdentity = r.getLocationIdentity();
+                    assert locationIdentity.isMutable();
+                    if (unprocessed.isMarked(r)) {
+                        if (identity.overlaps(locationIdentity)) {
+                            sortIntoList(r, b, result, nodeMap, unprocessed, null);
+                        } else {
+                            ++index;
+                            continue;
+                        }
+                    }
+                    int lastIndex = watchList.size() - 1;
+                    watchList.set(index, watchList.get(lastIndex));
+                    watchList.remove(lastIndex);
                 }
             }
         }
 
-        NodeStack stack = new NodeStack();
+        private static void sortIntoList(Node n, Block b, ArrayList<Node> result, NodeMap<Block> nodeMap, NodeBitMap unprocessed, Node excludeNode) {
+            assert unprocessed.isMarked(n) : n;
+            unprocessed.clear(n);
+
+            assert nodeMap.get(n) == b;
+
+            if (n instanceof PhiNode) {
+                return;
+            }
+
+            for (Node input : n.inputs()) {
+                if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) {
+                    sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode);
+                }
+            }
+
+            if (n instanceof ProxyNode) {
+                // Skip proxy nodes.
+            } else {
+                result.add(n);
+            }
+
+        }
 
-        // Start analysis with control flow ends.
-        for (Block b : cfg.postOrder()) {
-            FixedNode endNode = b.getEndNode();
-            if (isFixedEnd(endNode)) {
-                stack.push(endNode);
-                nodeToBlock.set(endNode, b);
+        @SuppressWarnings("unused")
+        protected void calcLatestBlock(Block earliestBlock, SchedulingStrategy strategy, Node currentNode, NodeMap<Block> currentNodeMap, NodeBitMap unreachableNodes,
+                        LocationIdentity constrainingLocation, BlockMap<ArrayList<FloatingReadNode>> watchListMap, BlockMap<List<Node>> latestBlockToNodesMap, NodeBitMap visited,
+                        boolean immutableGraph) {
+            Block latestBlock = null;
+            assert currentNode.hasUsages();
+            for (Node usage : currentNode.usages()) {
+                if (unreachableNodes != null && unreachableNodes.contains(usage)) {
+                    /*
+                     * Normally, dead nodes are deleted by the scheduler before we reach this point.
+                     * Only when the scheduler is asked to not modify a graph, we can see dead nodes
+                     * here.
+                     */
+                    assert immutableGraph;
+                    continue;
+                }
+                latestBlock = calcBlockForUsage(currentNode, usage, latestBlock, currentNodeMap);
             }
+
+            if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
+                while (latestBlock.getLoopDepth() > earliestBlock.getLoopDepth() && latestBlock != earliestBlock.getDominator()) {
+                    latestBlock = latestBlock.getDominator();
+                }
+            }
+
+            if (latestBlock != earliestBlock && latestBlock != earliestBlock.getDominator() && constrainingLocation != null) {
+                latestBlock = checkKillsBetween(earliestBlock, latestBlock, constrainingLocation);
+            }
+
+            selectLatestBlock(currentNode, earliestBlock, latestBlock, currentNodeMap, watchListMap, constrainingLocation, latestBlockToNodesMap);
         }
 
-        processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+        private static Block calcBlockForUsage(Node node, Node usage, Block startBlock, NodeMap<Block> currentNodeMap) {
+            assert !(node instanceof PhiNode);
+            Block currentBlock = startBlock;
+            if (usage instanceof PhiNode) {
+                // An input to a PhiNode is used at the end of the predecessor block that
+                // corresponds to the PhiNode input. One PhiNode can use an input multiple times.
+                PhiNode phi = (PhiNode) usage;
+                AbstractMergeNode merge = phi.merge();
+                Block mergeBlock = currentNodeMap.get(merge);
+                for (int i = 0; i < phi.valueCount(); ++i) {
+                    if (phi.valueAt(i) == node) {
+                        Block otherBlock = mergeBlock.getPredecessors().get(i);
+                        currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+                    }
+                }
+            } else if (usage instanceof AbstractBeginNode) {
+                AbstractBeginNode abstractBeginNode = (AbstractBeginNode) usage;
+                if (abstractBeginNode instanceof StartNode) {
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, currentNodeMap.get(abstractBeginNode));
+                } else {
+                    Block otherBlock = currentNodeMap.get(abstractBeginNode).getDominator();
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+                }
+            } else {
+                // All other types of usages: Put the input into the same block as the usage.
+                Block otherBlock = currentNodeMap.get(usage);
+                currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, otherBlock);
+            }
+            return currentBlock;
+        }
+
+        private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, NodeBitMap unreachableNodes,
+                        boolean immutableGraph) {
+
+            BitSet floatingReads = new BitSet(cfg.getBlocks().size());
+
+            // Add begin nodes as the first entry and set the block for phi nodes.
+            for (Block b : cfg.getBlocks()) {
+                AbstractBeginNode beginNode = b.getBeginNode();
+                ArrayList<Node> nodes = new ArrayList<>();
+                nodeToBlock.set(beginNode, b);
+                nodes.add(beginNode);
+                blockToNodes.put(b, nodes);
+
+                if (beginNode instanceof AbstractMergeNode) {
+                    AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
+                    for (PhiNode phi : mergeNode.phis()) {
+                        nodeToBlock.set(phi, b);
+                    }
+                } else if (beginNode instanceof LoopExitNode) {
+                    LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+                    for (ProxyNode proxy : loopExitNode.proxies()) {
+                        nodeToBlock.set(proxy, b);
+                    }
+                }
+            }
 
-        // Visit back input edges of loop phis.
-        boolean changed;
-        boolean unmarkedPhi;
-        do {
-            changed = false;
-            unmarkedPhi = false;
-            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
-                for (PhiNode phi : loopBegin.phis()) {
-                    if (visited.isMarked(phi)) {
-                        for (int i = 0; i < loopBegin.getLoopEndCount(); ++i) {
-                            Node node = phi.valueAt(i + loopBegin.forwardEndCount());
-                            if (node != null && !visited.isMarked(node)) {
-                                changed = true;
-                                stack.push(node);
-                                processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+            NodeStack stack = new NodeStack();
+
+            // Start analysis with control flow ends.
+            for (Block b : cfg.postOrder()) {
+                FixedNode endNode = b.getEndNode();
+                if (isFixedEnd(endNode)) {
+                    stack.push(endNode);
+                    nodeToBlock.set(endNode, b);
+                }
+            }
+
+            processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+
+            // Visit back input edges of loop phis.
+            boolean changed;
+            boolean unmarkedPhi;
+            do {
+                changed = false;
+                unmarkedPhi = false;
+                for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
+                    for (PhiNode phi : loopBegin.phis()) {
+                        if (visited.isMarked(phi)) {
+                            for (int i = 0; i < loopBegin.getLoopEndCount(); ++i) {
+                                Node node = phi.valueAt(i + loopBegin.forwardEndCount());
+                                if (node != null && !visited.isMarked(node)) {
+                                    changed = true;
+                                    stack.push(node);
+                                    processStack(cfg, blockToNodes, nodeToBlock, visited, floatingReads, stack);
+                                }
                             }
+                        } else {
+                            unmarkedPhi = true;
                         }
-                    } else {
-                        unmarkedPhi = true;
+                    }
+                }
+
+                /*
+                 * the processing of one loop phi could have marked a previously checked loop phi,
+                 * therefore this needs to be iterative.
+                 */
+            } while (unmarkedPhi && changed);
+
+            // Check for dead nodes.
+            if (visited.getCounter() < graph.getNodeCount()) {
+                for (Node n : graph.getNodes()) {
+                    if (!visited.isMarked(n)) {
+                        if (!immutableGraph) {
+                            n.clearInputs();
+                            n.markDeleted();
+                        } else if (unreachableNodes != null) {
+                            /*
+                             * We are not allowed to modify the graph, so remember that node is
+                             * dead.
+                             */
+                            unreachableNodes.mark(n);
+                        }
                     }
                 }
             }
 
-            /*
-             * the processing of one loop phi could have marked a previously checked loop phi,
-             * therefore this needs to be iterative.
-             */
-        } while (unmarkedPhi && changed);
+            // Add end nodes as the last nodes in each block.
+            for (Block b : cfg.getBlocks()) {
+                FixedNode endNode = b.getEndNode();
+                if (isFixedEnd(endNode)) {
+                    if (endNode != b.getBeginNode()) {
+                        addNode(blockToNodes, b, endNode);
+                    }
+                }
+            }
+
+            if (!floatingReads.isEmpty()) {
+                for (Block b : cfg.getBlocks()) {
+                    if (floatingReads.get(b.getId())) {
+                        resortEarliestWithinBlock(b, blockToNodes, nodeToBlock, visited);
+                    }
+                }
+            }
+
+            assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
+        }
+
+        private static boolean isFixedEnd(FixedNode endNode) {
+            return endNode instanceof ControlSplitNode || endNode instanceof ControlSinkNode || endNode instanceof AbstractEndNode;
+        }
+
+        private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
+            ArrayList<FloatingReadNode> watchList = new ArrayList<>();
+            List<Node> oldList = blockToNodes.get(b);
+            AbstractBeginNode beginNode = b.getBeginNode();
+            for (Node n : oldList) {
+                if (n instanceof FloatingReadNode) {
+                    FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                    LocationIdentity locationIdentity = floatingReadNode.getLocationIdentity();
+                    MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
+                    if (locationIdentity.isMutable() && lastLocationAccess != null) {
+                        ValueNode lastAccessLocation = lastLocationAccess.asNode();
+                        if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) {
+                            // This node's last access location is within this block. Add to watch
+                            // list when processing the last access location.
+                        } else {
+                            watchList.add(floatingReadNode);
+                        }
+                    }
+                }
+            }
+
+            ArrayList<Node> newList = new ArrayList<>(oldList.size());
+            assert oldList.get(0) == beginNode;
+            unprocessed.clear(beginNode);
+            newList.add(beginNode);
+            for (int i = 1; i < oldList.size(); ++i) {
+                Node n = oldList.get(i);
+                if (unprocessed.isMarked(n)) {
+                    if (n instanceof MemoryNode) {
+                        if (n instanceof MemoryCheckpoint) {
+                            assert n instanceof FixedNode;
+                            if (watchList.size() > 0) {
+                                // Check whether we need to commit reads from the watch list.
+                                checkWatchList(b, nodeToBlock, unprocessed, newList, watchList, n);
+                            }
+                        }
+                        // Add potential dependent reads to the watch list.
+                        for (Node usage : n.usages()) {
+                            if (usage instanceof FloatingReadNode) {
+                                FloatingReadNode floatingReadNode = (FloatingReadNode) usage;
+                                if (nodeToBlock.get(floatingReadNode) == b && floatingReadNode.getLastLocationAccess() == n && !(n instanceof MemoryPhiNode)) {
+                                    watchList.add(floatingReadNode);
+                                }
+                            }
+                        }
+                    }
+                    assert unprocessed.isMarked(n);
+                    unprocessed.clear(n);
+                    newList.add(n);
+                } else {
+                    // This node was pulled up.
+                    assert !(n instanceof FixedNode) : n;
+                }
+            }
+
+            for (Node n : newList) {
+                unprocessed.mark(n);
+            }
+
+            assert newList.size() == oldList.size();
+            blockToNodes.put(b, newList);
+        }
 
-        // Check for dead nodes.
-        if (visited.getCounter() < graph.getNodeCount()) {
-            for (Node n : graph.getNodes()) {
-                if (!visited.isMarked(n)) {
-                    if (!immutableGraph) {
-                        n.clearInputs();
-                        n.markDeleted();
-                    } else if (unreachableNodes != null) {
-                        /* We are not allowed to modify the graph, so remember that node is dead. */
-                        unreachableNodes.mark(n);
+        private static void addNode(BlockMap<List<Node>> blockToNodes, Block b, Node endNode) {
+            assert !blockToNodes.get(b).contains(endNode) : endNode;
+            blockToNodes.get(b).add(endNode);
+        }
+
+        private static void processStack(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, BitSet floatingReads, NodeStack stack) {
+            Block startBlock = cfg.getStartBlock();
+            while (!stack.isEmpty()) {
+                Node current = stack.peek();
+                if (visited.checkAndMarkInc(current)) {
+
+                    // Push inputs and predecessor.
+                    Node predecessor = current.predecessor();
+                    if (predecessor != null) {
+                        stack.push(predecessor);
+                    }
+
+                    if (current instanceof PhiNode) {
+                        PhiNode phiNode = (PhiNode) current;
+                        AbstractMergeNode merge = phiNode.merge();
+                        for (int i = 0; i < merge.forwardEndCount(); ++i) {
+                            Node input = phiNode.valueAt(i);
+                            if (input != null) {
+                                stack.push(input);
+                            }
+                        }
+                    } else if (current instanceof ProxyNode) {
+                        ProxyNode proxyNode = (ProxyNode) current;
+                        for (Node input : proxyNode.inputs()) {
+                            if (input != proxyNode.proxyPoint()) {
+                                stack.push(input);
+                            }
+                        }
+                    } else if (current instanceof FrameState) {
+                        for (Node input : current.inputs()) {
+                            if (input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                // Ignore the cycle.
+                            } else {
+                                stack.push(input);
+                            }
+                        }
+                    } else {
+                        current.pushInputs(stack);
+                    }
+                } else {
+
+                    stack.pop();
+
+                    if (nodeToBlock.get(current) == null) {
+                        Block curBlock = cfg.blockFor(current);
+                        if (curBlock == null) {
+                            assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
+                            Block earliest = startBlock;
+                            for (Node input : current.inputs()) {
+                                Block inputEarliest = nodeToBlock.get(input);
+                                if (inputEarliest == null) {
+                                    assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current : current;
+                                } else {
+                                    assert inputEarliest != null;
+                                    if (inputEarliest.getEndNode() == input) {
+                                        // This is the last node of the block.
+                                        if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
+                                            // Keep regular inputEarliest.
+                                        } else if (input instanceof ControlSplitNode) {
+                                            inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
+                                        } else {
+                                            assert inputEarliest.getSuccessorCount() == 1;
+                                            assert !(input instanceof AbstractEndNode);
+                                            // Keep regular inputEarliest
+                                        }
+                                    }
+                                    if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
+                                        earliest = inputEarliest;
+                                    }
+                                }
+                            }
+                            curBlock = earliest;
+                        }
+                        assert curBlock != null;
+                        addNode(blockToNodes, curBlock, current);
+                        nodeToBlock.set(current, curBlock);
+                        if (current instanceof FloatingReadNode) {
+                            FloatingReadNode floatingReadNode = (FloatingReadNode) current;
+                            if (curBlock.canKill(floatingReadNode.getLocationIdentity())) {
+                                floatingReads.set(curBlock.getId());
+                            }
+                        }
                     }
                 }
             }
         }
 
-        // Add end nodes as the last nodes in each block.
-        for (Block b : cfg.getBlocks()) {
-            FixedNode endNode = b.getEndNode();
-            if (isFixedEnd(endNode)) {
-                if (endNode != b.getBeginNode()) {
-                    addNode(blockToNodes, b, endNode);
-                }
-            }
-        }
-
-        if (!floatingReads.isEmpty()) {
-            for (Block b : cfg.getBlocks()) {
-                if (floatingReads.get(b.getId())) {
-                    resortEarliestWithinBlock(b, blockToNodes, nodeToBlock, visited);
-                }
-            }
-        }
-
-        assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
-    }
+        public String printScheduleHelper(String desc) {
+            Formatter buf = new Formatter();
+            buf.format("=== %s / %s ===%n", getCFG().getStartBlock().getBeginNode().graph(), desc);
+            for (Block b : getCFG().getBlocks()) {
+                buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
+                buf.format("dom: %s. ", b.getDominator());
+                buf.format("preds: %s. ", b.getPredecessors());
+                buf.format("succs: %s ====%n", b.getSuccessors());
 
-    private static boolean isFixedEnd(FixedNode endNode) {
-        return endNode instanceof ControlSplitNode || endNode instanceof ControlSinkNode || endNode instanceof AbstractEndNode;
-    }
-
-    private static void resortEarliestWithinBlock(Block b, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap unprocessed) {
-        ArrayList<FloatingReadNode> watchList = new ArrayList<>();
-        List<Node> oldList = blockToNodes.get(b);
-        AbstractBeginNode beginNode = b.getBeginNode();
-        for (Node n : oldList) {
-            if (n instanceof FloatingReadNode) {
-                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
-                LocationIdentity locationIdentity = floatingReadNode.getLocationIdentity();
-                MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess();
-                if (locationIdentity.isMutable() && lastLocationAccess != null) {
-                    ValueNode lastAccessLocation = lastLocationAccess.asNode();
-                    if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) {
-                        // This node's last access location is within this block. Add to watch list
-                        // when processing the last access location.
-                    } else {
-                        watchList.add(floatingReadNode);
+                if (blockToNodesMap.get(b) != null) {
+                    for (Node n : nodesFor(b)) {
+                        printNode(n);
+                    }
+                } else {
+                    for (Node n : b.getNodes()) {
+                        printNode(n);
                     }
                 }
             }
-        }
-
-        ArrayList<Node> newList = new ArrayList<>(oldList.size());
-        assert oldList.get(0) == beginNode;
-        unprocessed.clear(beginNode);
-        newList.add(beginNode);
-        for (int i = 1; i < oldList.size(); ++i) {
-            Node n = oldList.get(i);
-            if (unprocessed.isMarked(n)) {
-                if (n instanceof MemoryNode) {
-                    if (n instanceof MemoryCheckpoint) {
-                        assert n instanceof FixedNode;
-                        if (watchList.size() > 0) {
-                            // Check whether we need to commit reads from the watch list.
-                            checkWatchList(b, nodeToBlock, unprocessed, newList, watchList, n);
-                        }
-                    }
-                    // Add potential dependent reads to the watch list.
-                    for (Node usage : n.usages()) {
-                        if (usage instanceof FloatingReadNode) {
-                            FloatingReadNode floatingReadNode = (FloatingReadNode) usage;
-                            if (nodeToBlock.get(floatingReadNode) == b && floatingReadNode.getLastLocationAccess() == n && !(n instanceof MemoryPhiNode)) {
-                                watchList.add(floatingReadNode);
-                            }
-                        }
-                    }
-                }
-                assert unprocessed.isMarked(n);
-                unprocessed.clear(n);
-                newList.add(n);
-            } else {
-                // This node was pulled up.
-                assert !(n instanceof FixedNode) : n;
-            }
-        }
-
-        for (Node n : newList) {
-            unprocessed.mark(n);
+            buf.format("%n");
+            return buf.toString();
         }
 
-        assert newList.size() == oldList.size();
-        blockToNodes.put(b, newList);
-    }
-
-    private static void addNode(BlockMap<List<Node>> blockToNodes, Block b, Node endNode) {
-        assert !blockToNodes.get(b).contains(endNode) : endNode;
-        blockToNodes.get(b).add(endNode);
-    }
-
-    private static void processStack(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, BitSet floatingReads, NodeStack stack) {
-        Block startBlock = cfg.getStartBlock();
-        while (!stack.isEmpty()) {
-            Node current = stack.peek();
-            if (visited.checkAndMarkInc(current)) {
-
-                // Push inputs and predecessor.
-                Node predecessor = current.predecessor();
-                if (predecessor != null) {
-                    stack.push(predecessor);
+        private static void printNode(Node n) {
+            Formatter buf = new Formatter();
+            buf.format("%s", n);
+            if (n instanceof MemoryCheckpoint.Single) {
+                buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
+            } else if (n instanceof MemoryCheckpoint.Multi) {
+                buf.format(" // kills ");
+                for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                    buf.format("%s, ", locid);
                 }
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode frn = (FloatingReadNode) n;
+                buf.format(" // from %s", frn.getLocationIdentity());
+                buf.format(", lastAccess: %s", frn.getLastLocationAccess());
+                buf.format(", address: %s", frn.getAddress());
+            } else if (n instanceof GuardNode) {
+                buf.format(", anchor: %s", ((GuardNode) n).getAnchor());
+            }
+            Debug.log("%s", buf);
+        }
 
-                if (current instanceof PhiNode) {
-                    PhiNode phiNode = (PhiNode) current;
-                    AbstractMergeNode merge = phiNode.merge();
-                    for (int i = 0; i < merge.forwardEndCount(); ++i) {
-                        Node input = phiNode.valueAt(i);
-                        if (input != null) {
-                            stack.push(input);
-                        }
-                    }
-                } else if (current instanceof ProxyNode) {
-                    ProxyNode proxyNode = (ProxyNode) current;
-                    for (Node input : proxyNode.inputs()) {
-                        if (input != proxyNode.proxyPoint()) {
-                            stack.push(input);
-                        }
-                    }
-                } else if (current instanceof FrameState) {
-                    for (Node input : current.inputs()) {
-                        if (input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
-                            // Ignore the cycle.
-                        } else {
-                            stack.push(input);
-                        }
-                    }
-                } else {
-                    current.pushInputs(stack);
-                }
-            } else {
-
-                stack.pop();
+        public ControlFlowGraph getCFG() {
+            return cfg;
+        }
 
-                if (nodeToBlock.get(current) == null) {
-                    Block curBlock = cfg.blockFor(current);
-                    if (curBlock == null) {
-                        assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg.";
-                        Block earliest = startBlock;
-                        for (Node input : current.inputs()) {
-                            Block inputEarliest = nodeToBlock.get(input);
-                            if (inputEarliest == null) {
-                                assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current : current;
-                            } else {
-                                assert inputEarliest != null;
-                                if (inputEarliest.getEndNode() == input) {
-                                    // This is the last node of the block.
-                                    if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) {
-                                        // Keep regular inputEarliest.
-                                    } else if (input instanceof ControlSplitNode) {
-                                        inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor());
-                                    } else {
-                                        assert inputEarliest.getSuccessorCount() == 1;
-                                        assert !(input instanceof AbstractEndNode);
-                                        // Keep regular inputEarliest
-                                    }
-                                }
-                                if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
-                                    earliest = inputEarliest;
-                                }
-                            }
-                        }
-                        curBlock = earliest;
-                    }
-                    assert curBlock != null;
-                    addNode(blockToNodes, curBlock, current);
-                    nodeToBlock.set(current, curBlock);
-                    if (current instanceof FloatingReadNode) {
-                        FloatingReadNode floatingReadNode = (FloatingReadNode) current;
-                        if (curBlock.canKill(floatingReadNode.getLocationIdentity())) {
-                            floatingReads.set(curBlock.getId());
-                        }
-                    }
-                }
-            }
+        /**
+         * Gets the nodes in a given block.
+         */
+        public List<Node> nodesFor(Block block) {
+            return blockToNodesMap.get(block);
         }
     }
-
-    public String printScheduleHelper(String desc) {
-        Formatter buf = new Formatter();
-        buf.format("=== %s / %s / %s ===%n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, desc);
-        for (Block b : getCFG().getBlocks()) {
-            buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
-            buf.format("dom: %s. ", b.getDominator());
-            buf.format("preds: %s. ", b.getPredecessors());
-            buf.format("succs: %s ====%n", b.getSuccessors());
-            BlockMap<LocationSet> killSets = blockToKillSet;
-            if (killSets != null) {
-                buf.format("X block kills: %n");
-                if (killSets.get(b) != null) {
-                    for (LocationIdentity locId : killSets.get(b).getCopyAsList()) {
-                        buf.format("X %s killed by %s%n", locId, "dunno anymore");
-                    }
-                }
-            }
-
-            if (blockToNodesMap.get(b) != null) {
-                for (Node n : nodesFor(b)) {
-                    printNode(n);
-                }
-            } else {
-                for (Node n : b.getNodes()) {
-                    printNode(n);
-                }
-            }
-        }
-        buf.format("%n");
-        return buf.toString();
-    }
-
-    private static void printNode(Node n) {
-        Formatter buf = new Formatter();
-        buf.format("%s", n);
-        if (n instanceof MemoryCheckpoint.Single) {
-            buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
-        } else if (n instanceof MemoryCheckpoint.Multi) {
-            buf.format(" // kills ");
-            for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
-                buf.format("%s, ", locid);
-            }
-        } else if (n instanceof FloatingReadNode) {
-            FloatingReadNode frn = (FloatingReadNode) n;
-            buf.format(" // from %s", frn.getLocationIdentity());
-            buf.format(", lastAccess: %s", frn.getLastLocationAccess());
-            buf.format(", address: %s", frn.getAddress());
-        } else if (n instanceof GuardNode) {
-            buf.format(", anchor: %s", ((GuardNode) n).getAnchor());
-        }
-        Debug.log("%s", buf);
-    }
-
-    public ControlFlowGraph getCFG() {
-        return cfg;
-    }
-
-    /**
-     * Gets the map from each block to the nodes in the block.
-     */
-    public BlockMap<List<Node>> getBlockToNodesMap() {
-        return blockToNodesMap;
-    }
-
-    public NodeMap<Block> getNodeToBlockMap() {
-        return this.nodeToBlockMap;
-    }
-
-    /**
-     * Gets the nodes in a given block.
-     */
-    public List<Node> nodesFor(Block block) {
-        return blockToNodesMap.get(block);
-    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -45,6 +45,7 @@
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.VirtualState;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
@@ -154,9 +155,10 @@
      */
     public static boolean assertSchedulableGraph(final StructuredGraph graph) {
         try {
-            final SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS);
+            final SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS);
             final Map<LoopBeginNode, NodeBitMap> loopEntryStates = Node.newIdentityMap();
-            schedule.apply(graph, false);
+            schedulePhase.apply(graph, false);
+            final ScheduleResult schedule = graph.getLastSchedule();
 
             BlockIteratorClosure<NodeBitMap> closure = new BlockIteratorClosure<NodeBitMap>() {
 
@@ -167,7 +169,7 @@
 
                 @Override
                 protected NodeBitMap processBlock(final Block block, final NodeBitMap currentState) {
-                    final List<Node> list = schedule.getBlockToNodesMap().get(block);
+                    final List<Node> list = graph.getLastSchedule().getBlockToNodesMap().get(block);
 
                     /*
                      * A stateAfter is not valid directly after its associated state split, but
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Tue Jan 05 16:42:05 2016 -0800
@@ -56,6 +56,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.VirtualState;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
@@ -141,32 +142,35 @@
         this.channel = channel;
     }
 
-    public void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException {
+    public void print(Graph graph, String title) throws IOException {
         writeByte(BEGIN_GRAPH);
         writePoolObject(title);
-        writeGraph(graph, predefinedSchedule);
+        writeGraph(graph);
         flush();
     }
 
     private void writeGraph(Graph graph) throws IOException {
-        writeGraph(graph, null);
-    }
+        ScheduleResult scheduleResult = null;
+        if (graph instanceof StructuredGraph) {
+
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            scheduleResult = structuredGraph.getLastSchedule();
+            if (scheduleResult == null) {
 
-    private void writeGraph(Graph graph, SchedulePhase predefinedSchedule) throws IOException {
-        SchedulePhase schedule = predefinedSchedule;
-        if (schedule == null) {
-            // Also provide a schedule when an error occurs
-            if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
-                try {
-                    schedule = new SchedulePhase();
-                    schedule.apply((StructuredGraph) graph);
-                } catch (Throwable t) {
+                // Also provide a schedule when an error occurs
+                if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
+                    try {
+                        SchedulePhase schedule = new SchedulePhase();
+                        schedule.apply(structuredGraph);
+                    } catch (Throwable t) {
+                    }
                 }
+
             }
         }
-        ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
-        BlockMap<List<Node>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
-        NodeMap<Block> nodeToBlocks = schedule == null ? null : schedule.getNodeToBlockMap();
+        ControlFlowGraph cfg = scheduleResult == null ? null : scheduleResult.getCFG();
+        BlockMap<List<Node>> blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap();
+        NodeMap<Block> nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap();
         List<Block> blocks = cfg == null ? null : cfg.getBlocks();
         writeNodes(graph, nodeToBlocks, cfg);
         writeBlocks(blocks, blockToNodes);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Jan 05 16:42:05 2016 -0800
@@ -57,12 +57,12 @@
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.StateSplit;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
 import com.oracle.graal.nodes.calc.FloatingNode;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 /**
  * Utility for printing Graal IR at various compilation phases.
@@ -73,7 +73,7 @@
     protected LIR lir;
     protected NodeLIRBuilder nodeLirGenerator;
     protected ControlFlowGraph cfg;
-    protected SchedulePhase schedule;
+    protected ScheduleResult schedule;
     protected ResolvedJavaMethod method;
 
     /**
@@ -564,7 +564,7 @@
         end("intervals");
     }
 
-    public void printSchedule(String message, SchedulePhase theSchedule) {
+    public void printSchedule(String message, ScheduleResult theSchedule) {
         schedule = theSchedule;
         cfg = schedule.getCFG();
         printedNodes = new NodeBitMap(cfg.graph);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Tue Jan 05 16:42:05 2016 -0800
@@ -40,7 +40,7 @@
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.code.DisassemblerProvider;
 import com.oracle.graal.compiler.common.GraalOptions;
@@ -56,8 +56,8 @@
 import com.oracle.graal.lir.LIR;
 import com.oracle.graal.lir.debug.IntervalDumper;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 /**
  * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the
@@ -188,8 +188,8 @@
                 cfgPrinter.printIntervals(message, delayedIntervals);
                 delayedIntervals = null;
             }
-        } else if (object instanceof SchedulePhase) {
-            cfgPrinter.printSchedule(message, (SchedulePhase) object);
+        } else if (object instanceof ScheduleResult) {
+            cfgPrinter.printSchedule(message, (ScheduleResult) object);
         } else if (object instanceof StructuredGraph) {
             if (cfgPrinter.cfg == null) {
                 StructuredGraph graph = (StructuredGraph) object;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.PrintBackendCFG;
 import static com.oracle.graal.compiler.common.GraalOptions.PrintBinaryGraphs;
 import static com.oracle.graal.compiler.common.GraalOptions.PrintCFG;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugConfig;
@@ -35,6 +34,7 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodeinfo.Verbosity;
 import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(DebugConfigCustomizer.class)
 public class GraalDebugConfigCustomizer implements DebugConfigCustomizer {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinter.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinter.java	Tue Jan 05 16:42:05 2016 -0800
@@ -28,7 +28,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import com.oracle.graal.graph.Graph;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 interface GraphPrinter extends Closeable {
 
@@ -42,7 +41,7 @@
      * Prints an entire {@link Graph} with the specified title, optionally using short names for
      * nodes.
      */
-    void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException;
+    void print(Graph graph, String title) throws IOException;
 
     /**
      * Ends the current group.
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -57,7 +57,6 @@
 import com.oracle.graal.debug.DebugDumpScope;
 import com.oracle.graal.debug.TTY;
 import com.oracle.graal.graph.Graph;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 //JaCoCo Exclude
 
@@ -202,10 +201,9 @@
                 // Save inline context for next dump.
                 previousInlineContext = inlineContext;
 
-                final SchedulePhase predefinedSchedule = getPredefinedSchedule();
                 try (Scope s = Debug.sandbox("PrintingGraph", null)) {
                     // Finally, output the graph.
-                    printer.print(graph, nextDumpId() + ":" + message, predefinedSchedule);
+                    printer.print(graph, nextDumpId() + ":" + message);
                 } catch (IOException e) {
                     failuresCount++;
                     printer = null;
@@ -248,16 +246,6 @@
         return result;
     }
 
-    private static SchedulePhase getPredefinedSchedule() {
-        SchedulePhase result = null;
-        for (Object o : Debug.context()) {
-            if (o instanceof SchedulePhase) {
-                result = (SchedulePhase) o;
-            }
-        }
-        return result;
-    }
-
     private void openScope(String name, int inlineDepth) {
         String prefix = inlineDepth == 0 ? Thread.currentThread().getName() + ":" : "";
         try {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Tue Jan 05 16:42:05 2016 -0800
@@ -48,6 +48,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.phases.schedule.SchedulePhase;
@@ -89,25 +90,26 @@
         endMethod();
     }
 
-    public void print(Graph graph, String title) {
-        print(graph, title, null);
-    }
-
     /**
      * Prints an entire {@link Graph} with the specified title, optionally using short names for
      * nodes.
      */
     @Override
-    public void print(Graph graph, String title, SchedulePhase predefinedSchedule) {
+    public void print(Graph graph, String title) {
         beginGraph(title);
         Set<Node> noBlockNodes = Node.newSet();
-        SchedulePhase schedule = predefinedSchedule;
-        if (schedule == null && tryToSchedule) {
-            if (PrintIdealGraphSchedule.getValue()) {
-                try {
-                    schedule = new SchedulePhase();
-                    schedule.apply((StructuredGraph) graph);
-                } catch (Throwable t) {
+        ScheduleResult schedule = null;
+        if (graph instanceof StructuredGraph) {
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            schedule = structuredGraph.getLastSchedule();
+            if (schedule == null && tryToSchedule) {
+                if (PrintIdealGraphSchedule.getValue()) {
+                    try {
+                        SchedulePhase schedulePhase = new SchedulePhase();
+                        schedulePhase.apply(structuredGraph);
+                        schedule = structuredGraph.getLastSchedule();
+                    } catch (Throwable t) {
+                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/NoDeadCodeVerifyHandler.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/NoDeadCodeVerifyHandler.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,13 +27,13 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.debug.DebugVerifyHandler;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64CountLeadingZerosNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,72 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.compiler.common.type.PrimitiveStamp;
+import com.oracle.graal.compiler.common.type.StampFactory;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import com.oracle.graal.lir.gen.ArithmeticLIRGeneratorTool;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.UnaryNode;
+import com.oracle.graal.nodes.spi.ArithmeticLIRLowerable;
+import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo
+public final class AArch64CountLeadingZerosNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<AArch64CountLeadingZerosNode> TYPE = NodeClass.create(AArch64CountLeadingZerosNode.class);
+
+    public AArch64CountLeadingZerosNode(ValueNode value) {
+        super(TYPE, StampFactory.forInteger(JavaKind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+    }
+
+    public static ValueNode tryFold(ValueNode value) {
+        if (value.isConstant()) {
+            JavaConstant c = value.asJavaConstant();
+            if (value.getStackKind() == JavaKind.Int) {
+                return ConstantNode.forInt(Integer.numberOfLeadingZeros(c.asInt()));
+            } else {
+                return ConstantNode.forInt(Long.numberOfLeadingZeros(c.asLong()));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode folded = tryFold(forValue);
+        return folded != null ? folded : this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+        builder.setResult(this, ((AArch64ArithmeticLIRGeneratorTool) gen).emitCountLeadingZeros(builder.operand(getValue())));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64FloatArithmeticSnippets.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,142 @@
+/*
+ * 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
+ * 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.aarch64;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Rem;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.graph.spi.CanonicalizerTool;
+import com.oracle.graal.lir.gen.ArithmeticLIRGeneratorTool;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.BinaryArithmeticNode;
+import com.oracle.graal.nodes.calc.RemNode;
+import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.replacements.Snippet;
+import com.oracle.graal.replacements.SnippetTemplate;
+import com.oracle.graal.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * AArch64 does not have a remainder operation. We use <code>n % d == n - Truncate(n / d) * d</code>
+ * for it instead. This is not correct for some edge cases, so we have to fix it up using these
+ * snippets.
+ */
+public class AArch64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemplates implements Snippets {
+
+    private final SnippetTemplate.SnippetInfo drem;
+    private final SnippetTemplate.SnippetInfo frem;
+
+    public AArch64FloatArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+        super(providers, snippetReflection, target);
+        drem = snippet(AArch64FloatArithmeticSnippets.class, "dremSnippet");
+        frem = snippet(AArch64FloatArithmeticSnippets.class, "fremSnippet");
+    }
+
+    public void lower(RemNode node, LoweringTool tool) {
+        // assert node.kind() == JavaKind.Float || node.kind() == JavaKind.Double;
+        // if (node instanceof SafeNode) {
+        // // We already introduced the necessary checks, nothing to do.
+        // return;
+        // }
+        // SnippetTemplate.SnippetInfo snippet = node.kind() == Kind.Double ? drem : frem;
+        // SnippetTemplate.Arguments args = new SnippetTemplate.Arguments(snippet,
+        // node.graph().getGuardsStage());
+        // args.add("x", node.x());
+        // args.add("y", node.y());
+        // args.add("isStrictFP", node.isStrictFP());
+        // template(args).instantiate(providers.getMetaAccess(), node,
+        // SnippetTemplate.DEFAULT_REPLACER,
+        // tool, args);
+        throw JVMCIError.unimplemented(node + ", " + tool);
+    }
+
+    @Snippet
+    public static double dremSnippet(double x, double y, @Snippet.ConstantParameter boolean isStrictFP) {
+        if (Double.isInfinite(x) || y == 0.0 || Double.isNaN(y)) {
+            return Double.NaN;
+        }
+        // -0.0 % 5.0 will result in 0.0 and not -0.0 if we don't check here.
+        if (Double.isInfinite(y) || x == 0.0) {
+            return x;
+        }
+        return safeRem(JavaKind.Double, x, y, isStrictFP);
+    }
+
+    @Snippet
+    public static float fremSnippet(float x, float y, @Snippet.ConstantParameter boolean isStrictFP) {
+        if (Float.isInfinite(x) || y == 0.0f || Float.isNaN(y)) {
+            return Float.NaN;
+        }
+        // -0.0 % 5.0 will result in 0.0 and not -0.0 if we don't check here.
+        if (Float.isInfinite(y) || x == 0.0f) {
+            return x;
+        }
+        return safeRem(JavaKind.Float, x, y, isStrictFP);
+    }
+
+    @NodeIntrinsic(SafeFloatRemNode.class)
+    private static native double safeRem(@Node.ConstantNodeParameter JavaKind kind, double x, double y, @Node.ConstantNodeParameter boolean isStrictFP);
+
+    @NodeIntrinsic(SafeFloatRemNode.class)
+    private static native float safeRem(@Node.ConstantNodeParameter JavaKind kind, float x, float y, @Node.ConstantNodeParameter boolean isStrictFP);
+
+    // Marker interface to distinguish untreated nodes from ones where we have installed the
+    // additional checks
+    private interface SafeNode {
+    }
+
+    @NodeInfo
+    // static class SafeFloatRemNode extends FloatRemNode implements SafeNode {
+    static class SafeFloatRemNode extends BinaryArithmeticNode<Rem> implements SafeNode {
+
+        public static final NodeClass<SafeFloatRemNode> TYPE = NodeClass.create(SafeFloatRemNode.class);
+
+        @SuppressWarnings("unused")
+        public SafeFloatRemNode(JavaKind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
+            super(TYPE, ArithmeticOpTable::getRem, x, y);
+        }
+
+        public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+            throw JVMCIError.unimplemented();
+        }
+
+        public void generate(NodeLIRBuilderTool generator) {
+            throw JVMCIError.unimplemented();
+        }
+
+        public Node canonical(CanonicalizerTool tool) {
+            throw JVMCIError.unimplemented();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64GraphBuilderPlugins.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,81 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.compiler.common.spi.ForeignCallsProvider;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugin;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins;
+import com.oracle.graal.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.replacements.IntegerSubstitutions;
+import com.oracle.graal.replacements.LongSubstitutions;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class AArch64GraphBuilderPlugins {
+
+    public static void register(Plugins plugins, ForeignCallsProvider foreignCalls) {
+        InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
+        invocationPlugins.defer(new Runnable() {
+            public void run() {
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long);
+                registerMathPlugins(invocationPlugins, foreignCalls);
+            }
+        });
+    }
+
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass);
+        r.register1("numberOfLeadingZeros", type, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                ValueNode folded = AArch64CountLeadingZerosNode.tryFold(value);
+                if (folded != null) {
+                    b.addPush(JavaKind.Int, folded);
+                } else {
+                    b.addPush(JavaKind.Int, new AArch64CountLeadingZerosNode(value));
+                }
+                return true;
+            }
+        });
+        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
+    }
+
+    @SuppressWarnings("unused")
+    private static void registerMathPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
+        // Registration r = new Registration(plugins, Math.class);
+        // r.register1("sin", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_SIN));
+        // r.register1("cos", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_COS));
+        // r.register1("tan", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_TAN));
+        // r.register1("exp", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_EXP));
+        // r.register1("log", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_LOG));
+        // r.register1("log10", Double.TYPE, new ForeignCallPlugin(foreignCalls, ARITHMETIC_LOG10));
+        // r.register2("pow", Double.TYPE, Double.TYPE, new ForeignCallPlugin(foreignCalls,
+        // ARITHMETIC_POW));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64IntegerArithmeticSnippets.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,232 @@
+/*
+ * 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
+ * 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.aarch64;
+
+import com.oracle.graal.api.replacements.SnippetReflectionProvider;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.graph.NodeClass;
+import com.oracle.graal.nodeinfo.NodeInfo;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.FixedBinaryNode;
+import com.oracle.graal.nodes.calc.IntegerDivNode;
+import com.oracle.graal.nodes.calc.IntegerRemNode;
+import com.oracle.graal.nodes.calc.UnsignedDivNode;
+import com.oracle.graal.nodes.calc.UnsignedRemNode;
+import com.oracle.graal.nodes.spi.LoweringTool;
+import com.oracle.graal.phases.util.Providers;
+import com.oracle.graal.replacements.Snippet;
+import com.oracle.graal.replacements.SnippetTemplate;
+import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.replacements.Snippets;
+
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
+ * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
+ * forward to the LIRGenerator.
+ */
+public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {
+
+    private final SnippetTemplate.SnippetInfo idiv;
+    private final SnippetTemplate.SnippetInfo ldiv;
+    private final SnippetTemplate.SnippetInfo irem;
+    private final SnippetTemplate.SnippetInfo lrem;
+
+    private final SnippetTemplate.SnippetInfo uidiv;
+    private final SnippetTemplate.SnippetInfo uldiv;
+    private final SnippetTemplate.SnippetInfo uirem;
+    private final SnippetTemplate.SnippetInfo ulrem;
+
+    public AArch64IntegerArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
+        super(providers, snippetReflection, target);
+        idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
+        ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
+        irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
+        lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");
+
+        uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
+        uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
+        uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
+        ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
+    }
+
+    public void lower(FixedBinaryNode node, LoweringTool tool) {
+        // assert node.kind() == JavaKind.Int || node.kind() == JavaKind.Long;
+        // SnippetTemplate.SnippetInfo snippet;
+        // if (node instanceof SafeNode) {
+        // // We already introduced the 0 division check, nothing to do.
+        // return;
+        // } else if (node instanceof IntegerDivNode) {
+        // snippet = node.kind() == JavaKind.Int ? idiv : ldiv;
+        // } else if (node instanceof IntegerRemNode) {
+        // snippet = node.kind() == JavaKind.Int ? irem : lrem;
+        // } else if (node instanceof UnsignedDivNode) {
+        // snippet = node.kind() == JavaKind.Int ? uidiv : uldiv;
+        // } else if (node instanceof UnsignedRemNode) {
+        // snippet = node.kind() == JavaKind.Int ? uirem : ulrem;
+        // } else {
+        // throw GraalInternalError.shouldNotReachHere();
+        // }
+        // Arguments args = new Arguments(snippet, node.graph().getGuardsStage());
+        // args.add("x", node.x());
+        // args.add("y", node.y());
+        // template(args).instantiate(providers.getMetaAccess(), node,
+        // SnippetTemplate.DEFAULT_REPLACER,
+        // args);
+        throw JVMCIError.unimplemented(node + ", " + tool);
+    }
+
+    @Snippet
+    public static int idivSnippet(int x, int y) {
+        checkForZero(y);
+        return safeDiv(JavaKind.Int, x, y);
+    }
+
+    @Snippet
+    public static long ldivSnippet(long x, long y) {
+        checkForZero(y);
+        return safeDiv(JavaKind.Long, x, y);
+    }
+
+    @Snippet
+    public static int iremSnippet(int x, int y) {
+        checkForZero(y);
+        return safeRem(JavaKind.Int, x, y);
+    }
+
+    @Snippet
+    public static long lremSnippet(long x, long y) {
+        checkForZero(y);
+        return safeRem(JavaKind.Long, x, y);
+    }
+
+    @Snippet
+    public static int uidivSnippet(int x, int y) {
+        checkForZero(y);
+        return safeUDiv(JavaKind.Int, x, y);
+    }
+
+    @Snippet
+    public static long uldivSnippet(long x, long y) {
+        checkForZero(y);
+        return safeUDiv(JavaKind.Long, x, y);
+    }
+
+    @Snippet
+    public static int uiremSnippet(int x, int y) {
+        checkForZero(y);
+        return safeURem(JavaKind.Int, x, y);
+    }
+
+    @Snippet
+    public static long ulremSnippet(long x, long y) {
+        checkForZero(y);
+        return safeURem(JavaKind.Long, x, y);
+    }
+
+    private static void checkForZero(int y) {
+        if (y == 0) {
+            throw new ArithmeticException("/ by zero.");
+        }
+    }
+
+    private static void checkForZero(long y) {
+        if (y == 0) {
+            throw new ArithmeticException("/ by zero.");
+        }
+    }
+
+    @NodeIntrinsic(SafeIntegerDivNode.class)
+    private static native int safeDiv(@ConstantNodeParameter JavaKind kind, int x, int y);
+
+    @NodeIntrinsic(SafeIntegerDivNode.class)
+    private static native long safeDiv(@ConstantNodeParameter JavaKind kind, long x, long y);
+
+    @NodeIntrinsic(SafeIntegerRemNode.class)
+    private static native int safeRem(@ConstantNodeParameter JavaKind kind, int x, int y);
+
+    @NodeIntrinsic(SafeIntegerRemNode.class)
+    private static native long safeRem(@ConstantNodeParameter JavaKind kind, long x, long y);
+
+    @NodeIntrinsic(SafeUnsignedDivNode.class)
+    private static native int safeUDiv(@ConstantNodeParameter JavaKind kind, int x, int y);
+
+    @NodeIntrinsic(SafeUnsignedDivNode.class)
+    private static native long safeUDiv(@ConstantNodeParameter JavaKind kind, long x, long y);
+
+    @NodeIntrinsic(SafeUnsignedRemNode.class)
+    private static native int safeURem(@ConstantNodeParameter JavaKind kind, int x, int y);
+
+    @NodeIntrinsic(SafeUnsignedRemNode.class)
+    private static native long safeURem(@ConstantNodeParameter JavaKind kind, long x, long y);
+
+    // Marker interface to distinguish untreated nodes from ones where we have installed the
+    // additional checks
+    private interface SafeNode {
+    }
+
+    @NodeInfo
+    static class SafeIntegerDivNode extends IntegerDivNode implements SafeNode {
+        public static final NodeClass<SafeIntegerDivNode> TYPE = NodeClass.create(SafeIntegerDivNode.class);
+
+        @SuppressWarnings("unused")
+        public SafeIntegerDivNode(JavaKind kind, ValueNode x, ValueNode y) {
+            super(x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeIntegerRemNode extends IntegerRemNode implements SafeNode {
+        public static final NodeClass<SafeIntegerRemNode> TYPE = NodeClass.create(SafeIntegerRemNode.class);
+
+        @SuppressWarnings("unused")
+        public SafeIntegerRemNode(JavaKind kind, ValueNode x, ValueNode y) {
+            super(x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
+        public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
+
+        @SuppressWarnings("unused")
+        public SafeUnsignedDivNode(JavaKind kind, ValueNode x, ValueNode y) {
+            super(x, y);
+        }
+    }
+
+    @NodeInfo
+    static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
+        public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
+
+        @SuppressWarnings("unused")
+        public SafeUnsignedRemNode(JavaKind kind, ValueNode x, ValueNode y) {
+            super(x, y);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64IntegerSubstitutions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,55 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+import com.oracle.graal.replacements.nodes.BitScanForwardNode;
+
+/**
+ * AArch64 ISA offers a count leading zeros instruction which can be used to implement
+ * numberOfLeadingZeros more efficiently than using BitScanReverse.
+ */
+@ClassSubstitution(Integer.class)
+public class AArch64IntegerSubstitutions {
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(int i) {
+        return BitScanForwardNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int bitCount(int value) {
+        // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift
+        // instruction.
+        // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction
+        // this takes 10 instructions.
+        int x = value;
+        x = x - ((x & 0xaaaaaaaa) >>> 1);
+        x = (x & 0x33333333) + ((x & 0xcccccccc) >>> 2);
+        x = (x + (x >>> 4)) & 0x0f0f0f0f;
+        x = x + (x >>> 8);
+        x = x + (x >>> 16);
+        return x & 0x3f;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64LongSubstitutions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,57 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+import com.oracle.graal.replacements.nodes.BitScanForwardNode;
+
+/**
+ * Aarch64 ISA offers a count leading zeros instruction which can be used to implement
+ * numberOfLeadingZeros more efficiently than using BitScanReverse.
+ */
+@ClassSubstitution(Long.class)
+public class AArch64LongSubstitutions {
+
+    @MethodSubstitution
+    public static int numberOfTrailingZeros(long i) {
+        return BitScanForwardNode.scan(i);
+    }
+
+    @MethodSubstitution
+    public static int bitCount(long value) {
+        // Based on Warren, Hacker's Delight, slightly adapted to profit from Aarch64 add + shift
+        // instruction.
+        // Assuming the peephole optimizer optimizes all x - y >>> z into a single instruction
+        // this takes 11 instructions.
+        long x = value;
+        x = x - ((x & 0xaaaaaaaaaaaaaaaaL) >>> 1);
+        x = (x & 0x3333333333333333L) + ((x & 0xccccccccccccccccL) >>> 2);
+        x = (x + (x >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
+        x = x + (x >>> 8);
+        x = x + (x >>> 16);
+        x = x + (x >>> 32);
+        return (int) x & 0x7f;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.aarch64/src/com/oracle/graal/replacements/aarch64/AArch64MathSubstitutions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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.aarch64;
+
+import com.oracle.graal.api.replacements.ClassSubstitution;
+import com.oracle.graal.api.replacements.MethodSubstitution;
+
+/**
+ * Substitutions for {@link java.lang.Math} methods. Aarch64 does not offer special instructions to
+ * implement these functions, so implement them either in Java or call standard c library functions.
+ */
+@ClassSubstitution(java.lang.Math.class)
+public class AArch64MathSubstitutions {
+
+    @MethodSubstitution
+    public static double log(double x) {
+        return StrictMath.log(x);
+    }
+
+    @MethodSubstitution
+    public static double log10(double x) {
+        return StrictMath.log10(x);
+    }
+
+    @MethodSubstitution
+    public static double sin(double x) {
+        return StrictMath.sin(x);
+    }
+
+    @MethodSubstitution
+    public static double cos(double x) {
+        return StrictMath.cos(x);
+    }
+
+    @MethodSubstitution
+    public static double tan(double x) {
+        return StrictMath.tan(x);
+    }
+
+}
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java	Tue Jan 05 16:42:05 2016 -0800
@@ -190,7 +190,7 @@
             SnippetTemplate template = template(args);
             Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args);
             template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args);
-            graph.removeFloating(convert);
+            convert.safeDelete();
         }
     }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -63,7 +63,7 @@
         InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first();
         if (ion != null) {
             LogicNode ionNew = graph.unique(InstanceOfNode.create(ion.type(), ion.getValue(), profile));
-            graph.replaceFloating(ion, ionNew);
+            ion.replaceAtUsagesAndDelete(ionNew);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/InjectedDependencies.java	Tue Jan 05 16:42:05 2016 -0800
@@ -30,6 +30,7 @@
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeMirror;
 
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.replacements.verifier.InjectedDependencies.Dependency;
 
 public class InjectedDependencies implements Iterable<Dependency> {
@@ -67,7 +68,8 @@
 
         @Override
         public String inject(ExecutableElement inject) {
-            return String.format("injection.getReturnStamp(%s.class)", GeneratedPlugin.getErasedType(inject.getReturnType()));
+            NodeIntrinsic nodeIntrinsic = inject.getAnnotation(NodeIntrinsic.class);
+            return String.format("injection.getReturnStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nodeIntrinsic != null && nodeIntrinsic.returnStampIsNonNull());
         }
     }
 
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/PluginGenerator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -179,7 +179,7 @@
 
     protected static void createImports(PrintWriter out, List<GeneratedPlugin> plugins) {
         out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
-        out.printf("import jdk.vm.ci.service.ServiceProvider;\n");
+        out.printf("import com.oracle.graal.serviceprovider.ServiceProvider;\n");
         out.printf("\n");
         out.printf("import com.oracle.graal.nodes.ValueNode;\n");
         out.printf("import com.oracle.graal.nodes.graphbuilderconf.GraphBuilderContext;\n");
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -84,6 +84,7 @@
 import com.oracle.graal.nodes.extended.UnboxNode;
 import com.oracle.graal.nodes.extended.UnsafeLoadNode;
 import com.oracle.graal.nodes.extended.UnsafeStoreNode;
+import com.oracle.graal.nodes.java.AbstractNewArrayNode;
 import com.oracle.graal.nodes.java.AbstractNewObjectNode;
 import com.oracle.graal.nodes.java.AccessIndexedNode;
 import com.oracle.graal.nodes.java.ArrayLengthNode;
@@ -384,7 +385,7 @@
             return;
         }
         ValueNode hub = createReadHub(graph, loadHub.getValue(), tool);
-        graph.replaceFloating(loadHub, hub);
+        loadHub.replaceAtUsagesAndDelete(hub);
     }
 
     protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
@@ -631,7 +632,7 @@
         for (Node usage : commit.usages().snapshot()) {
             AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
             int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-            graph.replaceFloating(addObject, allocations[index]);
+            addObject.replaceAtUsagesAndDelete(allocations[index]);
         }
     }
 
@@ -791,6 +792,9 @@
             readArrayLength.setGuard(nullCheck);
             arrayLength = readArrayLength;
         } else {
+            if (array instanceof AbstractNewArrayNode) {
+                arrayLength = n.graph().addOrUnique(new PiNode(arrayLength, StampFactory.positiveInt()));
+            }
             arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
         }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue Jan 05 16:42:05 2016 -0800
@@ -38,7 +38,6 @@
 import jdk.vm.ci.meta.Signature;
 
 import com.oracle.graal.graph.Graph;
-import com.oracle.graal.graph.Node;
 import com.oracle.graal.java.FrameStateBuilder;
 import com.oracle.graal.java.GraphBuilderPhase;
 import com.oracle.graal.nodes.AbstractBeginNode;
@@ -52,7 +51,6 @@
 import com.oracle.graal.nodes.InvokeNode;
 import com.oracle.graal.nodes.LogicNode;
 import com.oracle.graal.nodes.MergeNode;
-import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.ValueNode;
@@ -264,11 +262,7 @@
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph);
 
         // Remove all frame states from inlinee
-        for (Node node : calleeGraph.getNodes()) {
-            if (node instanceof StateSplit) {
-                ((StateSplit) node).setStateAfter(null);
-            }
-        }
+        calleeGraph.clearAllStateAfter();
         new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph);
 
         InliningUtil.inline(invoke, calleeGraph, false, null);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -49,14 +49,14 @@
     }
 
     @Override
-    public Stamp getReturnStamp(Class<?> type) {
+    public Stamp getReturnStamp(Class<?> type, boolean nonNull) {
         JavaKind kind = JavaKind.fromJavaClass(type);
         if (kind == JavaKind.Object) {
             ResolvedJavaType returnType = metaAccess.lookupJavaType(type);
             if (wordTypes.isWord(returnType)) {
                 return wordTypes.getWordStamp(returnType);
             } else {
-                return StampFactory.declared(returnType);
+                return nonNull ? StampFactory.declaredNonNull(returnType) : StampFactory.declared(returnType);
             }
         } else {
             return StampFactory.forKind(kind);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Tue Jan 05 16:42:05 2016 -0800
@@ -44,8 +44,6 @@
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionValue;
 
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.debug.Debug;
@@ -91,6 +89,8 @@
 import com.oracle.graal.nodes.java.MonitorIdNode;
 import com.oracle.graal.nodes.spi.StampProvider;
 import com.oracle.graal.nodes.util.GraphUtil;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 
 /**
@@ -568,8 +568,7 @@
             registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
         }
         if (inlineScope.exceptionPlaceholderNode != null) {
-            inlineScope.exceptionPlaceholderNode.replaceAtUsages(exceptionValue);
-            inlineScope.exceptionPlaceholderNode.safeDelete();
+            inlineScope.exceptionPlaceholderNode.replaceAtUsagesAndDelete(exceptionValue);
         }
         deleteInvoke(invoke);
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Jan 05 16:42:05 2016 -0800
@@ -55,8 +55,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Signature;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
 import sun.misc.Launcher;
 
 import com.oracle.graal.api.replacements.ClassSubstitution;
@@ -92,6 +90,8 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.spi.Replacements;
 import com.oracle.graal.nodes.spi.StampProvider;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,7 +25,6 @@
 import static com.oracle.graal.compiler.common.GraalOptions.UseGraalInstrumentation;
 import static com.oracle.graal.debug.Debug.applyFormattingFlagsAndWidth;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.Required;
-import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.UseSnippetTemplateCache;
 import static java.util.FormattableFlags.ALTERNATE;
 import static jdk.vm.ci.meta.LocationIdentity.any;
 
@@ -38,10 +37,10 @@
 import java.util.Formattable;
 import java.util.Formatter;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -66,7 +65,6 @@
 import com.oracle.graal.debug.DebugCloseable;
 import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.debug.DebugTimer;
-import com.oracle.graal.debug.TTY;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.NodeClass;
@@ -216,16 +214,6 @@
             assert method.isStatic() : "snippet method must be static: " + method.format("%H.%n");
         }
 
-        private int templateCount;
-
-        void notifyNewTemplate() {
-            templateCount++;
-            if (templateCount == MaxTemplatesPerSnippet) {
-                TTY.print("WARNING: Exceeded %d templates for snippet %s%n" + "         Adjust maximum with %s system property%n", MaxTemplatesPerSnippet, method.format("%h.%n(%p)"),
-                                MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME);
-            }
-        }
-
         public ResolvedJavaMethod getMethod() {
             return method;
         }
@@ -548,18 +536,17 @@
     public abstract static class AbstractTemplates implements com.oracle.graal.api.replacements.SnippetTemplateCache {
 
         static final boolean UseSnippetTemplateCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetTemplateCache", "true"));
-
         protected final Providers providers;
         protected final SnippetReflectionProvider snippetReflection;
         protected final TargetDescription target;
-        private final ConcurrentHashMap<CacheKey, SnippetTemplate> templates;
+        private final Map<CacheKey, SnippetTemplate> templates;
 
         protected AbstractTemplates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
             this.providers = providers;
             this.snippetReflection = snippetReflection;
             this.target = target;
             if (UseSnippetTemplateCache) {
-                this.templates = new ConcurrentHashMap<>();
+                this.templates = Collections.synchronizedMap(new LRUCache<>(MaxTemplatesPerSnippet, MaxTemplatesPerSnippet));
             } else {
                 this.templates = null;
             }
@@ -615,6 +602,21 @@
         }
     }
 
+    private static final class LRUCache<K, V> extends LinkedHashMap<K, V> {
+        private static final long serialVersionUID = 1L;
+        private final int maxCacheSize;
+
+        public LRUCache(int initialCapacity, int maxCacheSize) {
+            super(initialCapacity, 0.75F, true);
+            this.maxCacheSize = maxCacheSize;
+        }
+
+        @Override
+        protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
+            return size() > maxCacheSize;
+        }
+    }
+
     // These values must be compared with equals() not '==' to support replay compilation.
     private static final Object UNUSED_PARAMETER = "UNUSED_PARAMETER";
     private static final Object CONSTANT_PARAMETER = "CONSTANT_PARAMETER";
@@ -858,9 +860,6 @@
             }
 
             Debug.metric("SnippetTemplateNodeCount[%#s]", args).add(nodes.size());
-            if (UseSnippetTemplateCache && args.cacheable) {
-                args.info.notifyNewTemplate();
-            }
             Debug.dump(snippet, "SnippetTemplate final state");
 
         } catch (Throwable ex) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -146,7 +146,7 @@
     }
 
     private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) {
-        if (destComponentType.getJavaKind() == JavaKind.Object) {
+        if (destComponentType.getJavaKind() == JavaKind.Object && !tool.getMetaAccessProvider().lookupJavaType(Object.class).equals(destComponentType)) {
             for (int i = 0; i < length; i++) {
                 ValueNode entry = tool.getEntry(src, srcPos + i);
                 ResolvedJavaType type = StampTool.typeOrNull(entry);
--- a/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/SalverDebugConfigCustomizer.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/SalverDebugConfigCustomizer.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,8 +27,7 @@
 import com.oracle.graal.debug.DebugConfig;
 import com.oracle.graal.debug.DebugConfigCustomizer;
 import com.oracle.graal.salver.handler.GraphDumpHandler;
-
-import jdk.vm.ci.service.ServiceProvider;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 
 @ServiceProvider(DebugConfigCustomizer.class)
 public class SalverDebugConfigCustomizer implements DebugConfigCustomizer {
--- a/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/SalverOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/SalverOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,9 +22,9 @@
  */
 package com.oracle.graal.salver;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 
 public final class SalverOptions {
 
--- a/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/dumper/GraphDumper.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.salver/src/com/oracle/graal/salver/dumper/GraphDumper.java	Tue Jan 05 16:42:05 2016 -0800
@@ -53,6 +53,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.VirtualState;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
@@ -90,13 +91,7 @@
         resolveMethodContext();
 
         try (Scope s = Debug.sandbox(getClass().getSimpleName(), null)) {
-            SchedulePhase predefinedSchedule = null;
-            for (Object obj : Debug.context()) {
-                if (obj instanceof SchedulePhase) {
-                    predefinedSchedule = (SchedulePhase) obj;
-                }
-            }
-            processGraph(graph, msg, predefinedSchedule);
+            processGraph(graph, msg);
         } catch (IOException e) {
             throw e;
         } catch (Throwable e) {
@@ -104,15 +99,24 @@
         }
     }
 
-    private void processGraph(Graph graph, String name, SchedulePhase predefinedSchedule) throws IOException {
-        SchedulePhase schedule = predefinedSchedule;
-        if (schedule == null) {
-            // Also provide a schedule when an error occurs
-            if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
-                if (graph instanceof StructuredGraph) {
-                    schedule = new SchedulePhase();
-                    schedule.apply((StructuredGraph) graph);
+    private void processGraph(Graph graph, String name) throws IOException {
+
+        ScheduleResult scheduleResult = null;
+        if (graph instanceof StructuredGraph) {
+
+            StructuredGraph structuredGraph = (StructuredGraph) graph;
+            scheduleResult = structuredGraph.getLastSchedule();
+            if (scheduleResult == null) {
+
+                // Also provide a schedule when an error occurs
+                if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) {
+                    try {
+                        SchedulePhase schedule = new SchedulePhase();
+                        schedule.apply(structuredGraph);
+                    } catch (Throwable t) {
+                    }
                 }
+
             }
         }
 
@@ -123,19 +127,19 @@
         DataDict graphDict = new DataDict();
         dataDict.put("graph", graphDict);
 
-        processNodes(graphDict, graph.getNodes(), schedule);
+        processNodes(graphDict, graph.getNodes(), scheduleResult);
 
-        if (schedule != null) {
-            ControlFlowGraph cfg = schedule.getCFG();
+        if (scheduleResult != null) {
+            ControlFlowGraph cfg = scheduleResult.getCFG();
             if (cfg != null) {
                 List<Block> blocks = cfg.getBlocks();
-                processBlocks(graphDict, blocks, schedule);
+                processBlocks(graphDict, blocks, scheduleResult);
             }
         }
         serializeAndFlush(createEventDictWithId("graph", dataDict));
     }
 
-    private static void processNodes(DataDict graphDict, NodeIterable<Node> nodes, SchedulePhase schedule) {
+    private static void processNodes(DataDict graphDict, NodeIterable<Node> nodes, ScheduleResult schedule) {
         Map<NodeClass<?>, Integer> classMap = new HashMap<>();
 
         DataList classList = new DataList();
@@ -172,7 +176,7 @@
         }
     }
 
-    private static void processNodeSchedule(DataDict nodeDict, Node node, SchedulePhase schedule) {
+    private static void processNodeSchedule(DataDict nodeDict, Node node, ScheduleResult schedule) {
         NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap();
         if (nodeToBlock != null) {
             if (nodeToBlock.isNew(node)) {
@@ -195,7 +199,7 @@
         }
     }
 
-    private static void processBlocks(DataDict graphDict, List<Block> blocks, SchedulePhase schedule) {
+    private static void processBlocks(DataDict graphDict, List<Block> blocks, ScheduleResult schedule) {
         BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap();
         DataList blockList = new DataList();
         graphDict.put("blocks", blockList);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.serviceprovider.processor/src/META-INF/services/javax.annotation.processing.Processor	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,1 @@
+com.oracle.graal.serviceprovider.processor.ServiceProviderProcessor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.serviceprovider.processor/src/com/oracle/graal/serviceprovider/processor/ServiceProviderProcessor.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.serviceprovider.processor;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+import com.oracle.graal.serviceprovider.ServiceProvider;
+
+/**
+ * Processes classes annotated with {@link ServiceProvider}. For a service defined by {@code S} and
+ * a class {@code P} implementing the service, this processor generates the file
+ * {@code META-INF/providers/P} whose contents are a single line containing the fully qualified name
+ * of {@code S}.
+ */
+@SupportedAnnotationTypes("com.oracle.graal.serviceprovider.ServiceProvider")
+public class ServiceProviderProcessor extends AbstractProcessor {
+
+    private final Set<TypeElement> processed = new HashSet<>();
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) {
+        if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) {
+            String msg = String.format("Service provider class %s must implement service interface %s", serviceProvider.getSimpleName(), serviceInterface);
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+            return false;
+        }
+
+        return true;
+    }
+
+    private void processElement(TypeElement serviceProvider) {
+        if (processed.contains(serviceProvider)) {
+            return;
+        }
+
+        processed.add(serviceProvider);
+        ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class);
+        if (annotation != null) {
+            try {
+                annotation.value();
+            } catch (MirroredTypeException ex) {
+                TypeMirror serviceInterface = ex.getTypeMirror();
+                if (verifyAnnotation(serviceInterface, serviceProvider)) {
+                    String interfaceName = ex.getTypeMirror().toString();
+                    createProviderFile(serviceProvider, interfaceName);
+                }
+            }
+        }
+    }
+
+    private void createProviderFile(TypeElement serviceProvider, String interfaceName) {
+        if (serviceProvider.getNestingKind().isNested()) {
+            // This is a simplifying constraint that means we don't have to
+            // processed the qualified name to insert '$' characters at
+            // the relevant positions.
+            String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName());
+            processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+            return;
+        }
+
+        String filename = "META-INF/providers/" + serviceProvider.getQualifiedName();
+        try {
+            FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider);
+            PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+            writer.println(interfaceName);
+            writer.close();
+        } catch (IOException e) {
+            processingEnv.getMessager().printMessage(isBug367599(e) ? Kind.NOTE : Kind.ERROR, e.getMessage(), serviceProvider);
+        }
+    }
+
+    /**
+     * Determines if a given exception is (most likely) caused by <a
+     * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
+     */
+    public static boolean isBug367599(Throwable t) {
+        if (t instanceof FilerException) {
+            for (StackTraceElement ste : t.getStackTrace()) {
+                if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
+                    // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
+                    return true;
+                }
+            }
+        }
+        if (t.getCause() != null) {
+            return isBug367599(t.getCause());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return true;
+        }
+
+        for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
+            assert element.getKind().isClass();
+            processElement((TypeElement) element);
+        }
+
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.serviceprovider/src/com/oracle/graal/serviceprovider/ServiceProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.serviceprovider;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jdk.vm.ci.services.Services;
+
+/**
+ * Annotates a service provider than can be loaded via {@linkplain Services#load(Class)} or
+ * {@link Services#loadSingle(Class, boolean)}.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ServiceProvider {
+
+    /**
+     * The interface or class defining the service implemented by the annotated class.
+     */
+    Class<?> value();
+}
--- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64OptimizedCallTargetInstrumentationFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -29,7 +29,6 @@
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.asm.Assembler;
 import com.oracle.graal.asm.Label;
@@ -40,6 +39,7 @@
 import com.oracle.graal.lir.asm.CompilationResultBuilder;
 import com.oracle.graal.lir.asm.FrameContext;
 import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.graal.truffle.hotspot.OptimizedCallTargetInstrumentation;
 import com.oracle.graal.truffle.hotspot.OptimizedCallTargetInstrumentationFactory;
 
--- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64RawNativeCallNodeFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64RawNativeCallNodeFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,11 +24,11 @@
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.hotspot.amd64.AMD64RawNativeCallNode;
 import com.oracle.graal.nodes.FixedWithNextNode;
 import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.graal.truffle.hotspot.nfi.RawNativeCallNodeFactory;
 
 @ServiceProvider(RawNativeCallNodeFactory.class)
--- a/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -31,7 +31,6 @@
 import jdk.vm.ci.code.CompilationResult;
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.code.Register;
-import jdk.vm.ci.service.ServiceProvider;
 
 import com.oracle.graal.asm.Assembler;
 import com.oracle.graal.asm.Label;
@@ -42,6 +41,7 @@
 import com.oracle.graal.lir.asm.CompilationResultBuilder;
 import com.oracle.graal.lir.asm.FrameContext;
 import com.oracle.graal.lir.framemap.FrameMap;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.graal.truffle.hotspot.OptimizedCallTargetInstrumentation;
 import com.oracle.graal.truffle.hotspot.OptimizedCallTargetInstrumentationFactory;
 
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Jan 05 16:42:05 2016 -0800
@@ -55,7 +55,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.runtime.JVMCI;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.api.runtime.GraalRuntime;
 import com.oracle.graal.compiler.target.Backend;
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntimeAccess.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntimeAccess.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,17 +25,17 @@
 import java.util.function.Supplier;
 
 import jdk.vm.ci.common.JVMCIError;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionValue;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
-import jdk.vm.ci.service.ServiceProvider;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.api.runtime.GraalJVMCICompiler;
 import com.oracle.graal.api.runtime.GraalRuntime;
 import com.oracle.graal.hotspot.HotSpotGraalCompilerFactory;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.truffle.api.TruffleRuntime;
 import com.oracle.truffle.api.TruffleRuntimeAccess;
 
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/nfi/HotSpotNativeFunctionInterfaceAccess.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/nfi/HotSpotNativeFunctionInterfaceAccess.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.truffle.hotspot.nfi;
 
-import jdk.vm.ci.service.ServiceProvider;
-
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.graal.truffle.hotspot.HotSpotTruffleRuntime;
 import com.oracle.nfi.api.NativeFunctionInterface;
 import com.oracle.nfi.api.NativeFunctionInterfaceAccess;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -24,15 +24,14 @@
 
 import java.util.Random;
 
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.OptionValue.OverrideScope;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.truffle.PartialEvaluator;
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/LazyInitializationTest.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/LazyInitializationTest.java	Tue Jan 05 16:42:05 2016 -0800
@@ -30,15 +30,18 @@
 import java.util.HashSet;
 import java.util.List;
 
-import jdk.vm.ci.options.OptionDescriptor;
-import jdk.vm.ci.options.OptionDescriptors;
-import jdk.vm.ci.options.OptionValue;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
 
 import org.junit.Assert;
 import org.junit.Test;
 
 import com.oracle.graal.compiler.CompilerThreadFactory;
+import com.oracle.graal.compiler.common.util.Util;
+import com.oracle.graal.options.OptionDescriptor;
+import com.oracle.graal.options.OptionDescriptors;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.OptionsParser;
+import com.oracle.graal.options.OptionsParser.OptionDescriptorsProvider;
 import com.oracle.graal.test.SubprocessUtil;
 
 /**
@@ -68,6 +71,9 @@
         spawnUnitTests("com.oracle.truffle.sl.test.SLTckTest");
     }
 
+    private static final String VERBOSE_PROPERTY = "LazyInitializationTest.verbose";
+    private static final boolean VERBOSE = Boolean.getBoolean(VERBOSE_PROPERTY);
+
     /**
      * Spawn a new VM, execute unit tests, and check which classes are loaded.
      */
@@ -87,12 +93,20 @@
 
         Process process = new ProcessBuilder(args).start();
 
+        if (VERBOSE) {
+            System.out.println("-----------------------------------------------------------------------------");
+            System.out.println(Util.join(args, " "));
+        }
         int testCount = 0;
         BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
         String line;
         while ((line = stdout.readLine()) != null) {
-            if (line.startsWith("[Loaded ")) {
-                int start = "[Loaded ".length();
+            if (VERBOSE) {
+                System.out.println(line);
+            }
+            int index = line.indexOf("[Loaded ");
+            if (index != -1) {
+                int start = index + "[Loaded ".length();
                 int end = line.indexOf(' ', start);
                 String loadedClass = line.substring(start, end);
                 if (isGraalClass(loadedClass)) {
@@ -109,11 +123,15 @@
                 testCount = Integer.parseInt(line.substring(start, end));
             }
         }
+        if (VERBOSE) {
+            System.out.println("-----------------------------------------------------------------------------");
+        }
 
-        Assert.assertNotEquals("test count", 0, testCount);
-        Assert.assertEquals("exit code", 0, process.waitFor());
+        String suffix = VERBOSE ? "" : " (use -D" + VERBOSE_PROPERTY + "=true to debug)";
+        Assert.assertNotEquals("test count" + suffix, 0, testCount);
+        Assert.assertEquals("exit code" + suffix, 0, process.waitFor());
 
-        checkAllowedGraalClasses(loadedGraalClasses);
+        checkAllowedGraalClasses(loadedGraalClasses, suffix);
     }
 
     private static boolean isGraalClass(String className) {
@@ -125,7 +143,7 @@
         }
     }
 
-    private void checkAllowedGraalClasses(List<Class<?>> loadedGraalClasses) {
+    private void checkAllowedGraalClasses(List<Class<?>> loadedGraalClasses, String errorMessageSuffix) {
         HashSet<Class<?>> whitelist = new HashSet<>();
 
         /*
@@ -150,7 +168,7 @@
             }
 
             if (!isGraalClassAllowed(cls)) {
-                Assert.fail("loaded class: " + cls.getName());
+                Assert.fail("loaded class: " + cls.getName() + errorMessageSuffix);
             }
         }
     }
@@ -171,16 +189,26 @@
             return true;
         }
 
-        if (OptionDescriptors.class.isAssignableFrom(cls)) {
+        if (OptionDescriptors.class.isAssignableFrom(cls) || OptionDescriptor.class.isAssignableFrom(cls)) {
             // If options are specified, the corresponding *_OptionDescriptors classes are loaded.
             return true;
         }
 
+        if (OptionDescriptorsProvider.class.isAssignableFrom(cls) || cls == OptionsParser.class) {
+            // Classes implementing Graal option loading
+            return true;
+        }
+
         if (OptionValue.class.isAssignableFrom(cls)) {
             // If options are specified, that may implicitly load a custom OptionValue subclass.
             return true;
         }
 
+        if (OptionValue.OverrideScope.class.isAssignableFrom(cls)) {
+            // Reading options can check override scopes
+            return true;
+        }
+
         if (hotSpotVMEventListener != null && hotSpotVMEventListener.isAssignableFrom(cls)) {
             // HotSpotVMEventListeners need to be loaded on JVMCI startup.
             return true;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLGetOptionBuiltin.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLGetOptionBuiltin.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.truffle.test.builtins;
 
-import jdk.vm.ci.options.OptionDescriptor;
-
+import com.oracle.graal.options.OptionDescriptor;
 import com.oracle.graal.truffle.TruffleCompilerOptions;
 import com.oracle.graal.truffle.TruffleCompilerOptions_OptionDescriptors;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLSetOptionBuiltin.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLSetOptionBuiltin.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.truffle.test.builtins;
 
-import jdk.vm.ci.options.OptionDescriptor;
-
+import com.oracle.graal.options.OptionDescriptor;
 import com.oracle.graal.truffle.TruffleCompilerOptions;
 import com.oracle.graal.truffle.TruffleCompilerOptions_OptionDescriptors;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultLoopNodeFactory.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultLoopNodeFactory.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,8 +22,7 @@
  */
 package com.oracle.graal.truffle;
 
-import jdk.vm.ci.service.ServiceProvider;
-
+import com.oracle.graal.serviceprovider.ServiceProvider;
 import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.api.nodes.RepeatingNode;
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Jan 05 16:42:05 2016 -0800
@@ -49,7 +49,7 @@
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.api.runtime.GraalRuntime;
 import com.oracle.graal.compiler.CompilerThreadFactory;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Jan 05 16:42:05 2016 -0800
@@ -40,10 +40,7 @@
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.service.Services;
+import jdk.vm.ci.services.Services;
 
 import com.oracle.graal.api.replacements.SnippetReflectionProvider;
 import com.oracle.graal.compiler.common.type.Stamp;
@@ -69,6 +66,9 @@
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
 import com.oracle.graal.nodes.virtual.VirtualInstanceNode;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.PhaseSuite;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Jan 05 16:42:05 2016 -0800
@@ -22,10 +22,10 @@
  */
 package com.oracle.graal.truffle;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-import jdk.vm.ci.options.StableOptionValue;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
+import com.oracle.graal.options.StableOptionValue;
 
 /**
  * Options for the Truffle compiler.
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleConstantReflectionProvider.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,7 +25,6 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaField;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MemoryAccessProvider;
@@ -67,8 +66,7 @@
         return graalConstantReflection.readConstantArrayElementForOffset(array, offset);
     }
 
-    public JavaConstant readConstantFieldValue(JavaField field0, JavaConstant receiver) {
-        ResolvedJavaField field = (ResolvedJavaField) field0;
+    public JavaConstant readConstantFieldValue(ResolvedJavaField field, JavaConstant receiver) {
         if (!field.isStatic() && receiver.isNonNull()) {
             JavaType fieldType = field.getType();
             if (field.isFinal() || field.getAnnotation(CompilationFinal.class) != null ||
@@ -100,11 +98,11 @@
         return true;
     }
 
-    public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) {
+    public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) {
         return graalConstantReflection.readFieldValue(field, receiver);
     }
 
-    public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
+    public JavaConstant readStableFieldValue(ResolvedJavaField field, JavaConstant receiver, boolean isDefaultStable) {
         return graalConstantReflection.readStableFieldValue(field, receiver, isDefaultStable);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/IsCompilationConstantNode.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/IsCompilationConstantNode.java	Tue Jan 05 16:42:05 2016 -0800
@@ -51,7 +51,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        graph().replaceFloating(this, ConstantNode.forBoolean(false, graph()));
+        replaceAtUsagesAndDelete(ConstantNode.forBoolean(false, graph()));
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -25,9 +25,9 @@
 import static com.oracle.graal.compiler.common.GraalOptions.EscapeAnalyzeOnly;
 
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.PhaseContext;
 
 public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
@@ -44,7 +44,7 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
         assert schedule == null;
         return new ReadEliminationClosure(cfg);
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Tue Jan 05 16:42:05 2016 -0800
@@ -47,6 +47,7 @@
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -59,12 +60,11 @@
 import com.oracle.graal.phases.graph.ReentrantBlockIterator;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
 
     protected final ControlFlowGraph cfg;
-    protected final SchedulePhase schedule;
+    protected final ScheduleResult schedule;
 
     protected final NodeMap<ValueNode> aliases;
     protected final BlockMap<GraphEffectList> blockEffects;
@@ -74,7 +74,7 @@
 
     protected boolean changed;
 
-    public EffectsClosure(SchedulePhase schedule, ControlFlowGraph cfg) {
+    public EffectsClosure(ScheduleResult schedule, ControlFlowGraph cfg) {
         this.schedule = schedule;
         this.cfg = cfg;
         this.aliases = cfg.graph.createNodeMap();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -33,6 +33,7 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.Simplifiable;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
@@ -75,14 +76,14 @@
         boolean changed = false;
         for (int iteration = 0; iteration < maxIterations; iteration++) {
             try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
-                SchedulePhase schedule;
+                ScheduleResult schedule;
                 ControlFlowGraph cfg;
                 if (unscheduled) {
                     schedule = null;
                     cfg = ControlFlowGraph.compute(graph, true, true, false, false);
                 } else {
-                    schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
-                    schedule.apply(graph, false);
+                    new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST).apply(graph, false);
+                    schedule = graph.getLastSchedule();
                     cfg = schedule.getCFG();
                 }
                 try (Scope scheduleScope = Debug.scope("EffectsPhaseWithSchedule", schedule)) {
@@ -127,5 +128,5 @@
         }
     }
 
-    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule, ControlFlowGraph cfg);
+    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, ScheduleResult schedule, ControlFlowGraph cfg);
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Jan 05 16:42:05 2016 -0800
@@ -45,6 +45,7 @@
 import com.oracle.graal.nodes.NamedLocationIdentity;
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.ProxyNode;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValueProxyNode;
 import com.oracle.graal.nodes.cfg.Block;
@@ -60,7 +61,6 @@
 import com.oracle.graal.nodes.type.StampTool;
 import com.oracle.graal.nodes.util.GraphUtil;
 import com.oracle.graal.nodes.virtual.VirtualArrayNode;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry;
 
 public class PEReadEliminationClosure extends PartialEscapeClosure<PEReadEliminationBlockState> {
@@ -73,7 +73,7 @@
         }
     }
 
-    public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+    public PEReadEliminationClosure(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
         super(schedule, metaAccess, constantReflection);
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jan 05 16:42:05 2016 -0800
@@ -150,6 +150,7 @@
         List<ValueNode> otherAllocations = new ArrayList<>(2);
         List<Boolean> ensureVirtual = new ArrayList<>(2);
         materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations);
+        assert fixed != null;
 
         materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> {
             for (ValueNode otherAllocation : otherAllocations) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jan 05 16:42:05 2016 -0800
@@ -62,6 +62,7 @@
 import com.oracle.graal.nodes.LoopExitNode;
 import com.oracle.graal.nodes.PhiNode;
 import com.oracle.graal.nodes.ProxyNode;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
 import com.oracle.graal.nodes.ValueProxyNode;
@@ -74,7 +75,6 @@
 import com.oracle.graal.nodes.spi.VirtualizerTool;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 import com.oracle.graal.phases.common.instrumentation.nodes.InstrumentationNode;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 
 public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockState<BlockT>> extends EffectsClosure<BlockT> {
 
@@ -128,7 +128,7 @@
      */
     public static final class Final extends PartialEscapeClosure<PartialEscapeBlockState.Final> {
 
-        public Final(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        public Final(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
             super(schedule, metaAccess, constantReflection);
         }
 
@@ -143,7 +143,7 @@
         }
     }
 
-    public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+    public PartialEscapeClosure(ScheduleResult schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
         super(schedule, schedule.getCFG());
         this.hasVirtualInputs = schedule.getCFG().graph.createNodeBitMap();
         this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, this);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Jan 05 16:42:05 2016 -0800
@@ -27,18 +27,16 @@
 
 import java.util.Set;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.ScheduleResult;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
-import com.oracle.graal.nodes.spi.VirtualizableAllocation;
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
+import com.oracle.graal.options.Option;
+import com.oracle.graal.options.OptionType;
+import com.oracle.graal.options.OptionValue;
 import com.oracle.graal.phases.BasePhase;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.schedule.SchedulePhase;
 import com.oracle.graal.phases.tiers.PhaseContext;
 
 public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
@@ -78,14 +76,14 @@
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
         if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) {
-            if (readElimination || graph.getNodes().filterInterface(VirtualizableAllocation.class).isNotEmpty()) {
+            if (readElimination || graph.hasVirtualizableAllocation()) {
                 runAnalysis(graph, context);
             }
         }
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+    protected Closure<?> createEffectsClosure(PhaseContext context, ScheduleResult schedule, ControlFlowGraph cfg) {
         for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) {
             virtual.resetObjectId();
         }
--- a/graal/com.oracle.nfi/src/com/oracle/nfi/NativeFunctionInterfaceRuntime.java	Tue Jan 05 16:32:42 2016 -0800
+++ b/graal/com.oracle.nfi/src/com/oracle/nfi/NativeFunctionInterfaceRuntime.java	Tue Jan 05 16:42:05 2016 -0800
@@ -49,13 +49,17 @@
         NativeFunctionInterfaceAccess access = null;
         Class<?> servicesClass = null;
         try {
-            servicesClass = Class.forName("jdk.vm.ci.service.Services");
+            servicesClass = Class.forName("jdk.vm.ci.services.Services");
         } catch (ClassNotFoundException e) {
             try {
-                // Legacy support
-                servicesClass = Class.forName("com.oracle.jvmci.service.Services");
+                servicesClass = Class.forName("jdk.vm.ci.service.Services");
             } catch (ClassNotFoundException e2) {
-                // JVMCI is unavailable
+                try {
+                    // Legacy support
+                    servicesClass = Class.forName("com.oracle.jvmci.service.Services");
+                } catch (ClassNotFoundException e3) {
+                    // JVMCI is unavailable
+                }
             }
         }
         if (servicesClass != null) {
--- a/mx.graal/mx_graal_8.py	Tue Jan 05 16:32:42 2016 -0800
+++ b/mx.graal/mx_graal_8.py	Tue Jan 05 16:42:05 2016 -0800
@@ -31,14 +31,16 @@
 import re
 
 import mx
-from mx_jvmci import JvmciJDKDeployedDist, jdkDeployedDists, add_bootclasspath_prepend, buildvms, get_jvmci_jdk, run_vm, VM, relativeVmLibDirInJdk, isJVMCIEnabled
+from mx_jvmci import JvmciJDKDeployedDist, JVMCIArchiveParticipant, jdkDeployedDists, add_bootclasspath_prepend, buildvms, get_jvmci_jdk, VM, relativeVmLibDirInJdk, isJVMCIEnabled
 from mx_jvmci import get_vm as _jvmci_get_vm
+from mx_jvmci import run_vm as _jvmci_run_vm
 from mx_gate import Task
 from sanitycheck import _noneAsEmptyList
 
 from mx_unittest import unittest
 from mx_graal_bench import dacapo
 import mx_gate
+import mx_unittest
 
 _suite = mx.suite('graal')
 
@@ -56,12 +58,18 @@
         return vm
 
 class GraalJDKDeployedDist(JvmciJDKDeployedDist):
-    def __init__(self):
-        JvmciJDKDeployedDist.__init__(self, 'GRAAL_HOTSPOT', compilers=['graal-economy', 'graal'])
+    def __init__(self, name, compilers=False, updatesGraalProperties=False):
+        JvmciJDKDeployedDist.__init__(self, name, compilers=compilers)
+        self.updatesGraalProperties = updatesGraalProperties
 
     def deploy(self, jdkDir):
         JvmciJDKDeployedDist.deploy(self, jdkDir)
-        self._updateGraalPropertiesFile(join(jdkDir, 'jre', 'lib'))
+        if self.updatesGraalProperties:
+            self._updateGraalPropertiesFile(join(jdkDir, 'jre', 'lib'))
+
+    def set_archiveparticipant(self):
+        dist = self.dist()
+        dist.set_archiveparticipant(GraalArchiveParticipant(dist))
 
     def _updateGraalPropertiesFile(self, jreLibDir):
         """
@@ -85,13 +93,14 @@
                 fp.write(os.linesep.join(content))
 
 jdkDeployedDists += [
-    JvmciJDKDeployedDist('GRAAL_NODEINFO'),
-    JvmciJDKDeployedDist('GRAAL_API'),
-    JvmciJDKDeployedDist('GRAAL_COMPILER'),
-    JvmciJDKDeployedDist('GRAAL'),
-    GraalJDKDeployedDist(),
-    JvmciJDKDeployedDist('GRAAL_TRUFFLE'),
-    JvmciJDKDeployedDist('GRAAL_TRUFFLE_HOTSPOT'),
+    GraalJDKDeployedDist('GRAAL_OPTIONS'),
+    GraalJDKDeployedDist('GRAAL_NODEINFO'),
+    GraalJDKDeployedDist('GRAAL_API'),
+    GraalJDKDeployedDist('GRAAL_COMPILER'),
+    GraalJDKDeployedDist('GRAAL_RUNTIME'),
+    GraalJDKDeployedDist('GRAAL_HOTSPOT', compilers=['graal-economy', 'graal'], updatesGraalProperties=True),
+    GraalJDKDeployedDist('GRAAL_TRUFFLE'),
+    GraalJDKDeployedDist('GRAAL_TRUFFLE_HOTSPOT'),
 ]
 
 mx_gate.add_jacoco_includes(['com.oracle.graal.*'])
@@ -169,7 +178,6 @@
 
     if args.ctwopts:
         # Replace spaces  with '#' since -G: options cannot contain spaces
-        # when they are collated in the "jvmci.options" system property
         vmargs.append('-G:CompileTheWorldConfig=' + re.sub(r'\s+', '#', args.ctwopts))
 
     if args.cp:
@@ -376,12 +384,65 @@
     else:
         print '{:>10}  {}'.format('<missing>', jvmLib)
 
+# Support for -G: options
+def _translateGOption(arg):
+    if arg.startswith('-G:+'):
+        if '=' in arg:
+            mx.abort('Mixing + and = in -G: option specification: ' + arg)
+        arg = '-Dgraal.option.' + arg[len('-G:+'):] + '=true'
+    elif arg.startswith('-G:-'):
+        if '=' in arg:
+            mx.abort('Mixing - and = in -G: option specification: ' + arg)
+        arg = '-Dgraal.option.' + arg[len('-G:+'):] + '=false'
+    elif arg.startswith('-G:'):
+        arg = '-Dgraal.option.' + arg[len('-G:'):]
+    return arg
+
+def run_vm(*positionalargs, **kwargs):
+    """run a Java program by executing the java executable in a Graal JDK"""
+
+    # convert positional args to a list so the first element can be updated
+    positionalargs = list(positionalargs)
+    args = positionalargs[0]
+    if '-G:+PrintFlags' in args and '-Xcomp' not in args:
+        mx.warn('Using -G:+PrintFlags may have no effect without -Xcomp as Graal initialization is lazy')
+    positionalargs[0] = map(_translateGOption, args)
+    return _jvmci_run_vm(*positionalargs, **kwargs)
+
+def _unittest_config_participant(config):
+    vmArgs, mainClass, mainClassArgs = config
+    if isJVMCIEnabled(get_vm()):
+        return (map(_translateGOption, vmArgs), mainClass, mainClassArgs)
+    return config
+
+mx_unittest.add_config_participant(_unittest_config_participant)
+
 mx.update_commands(_suite, {
+    'vm': [run_vm, '[-options] class [args...]'],
     'jdkartifactstats' : [jdkartifactstats, ''],
     'ctw': [ctw, '[-vmoptions|noinline|nocomplex|full]'],
     'microbench' : [microbench, '[VM options] [-- [JMH options]]'],
 })
 
+class GraalArchiveParticipant(JVMCIArchiveParticipant):
+    def __init__(self, dist):
+        JVMCIArchiveParticipant.__init__(self, dist)
+
+    def __add__(self, arcname, contents):
+        if arcname.startswith('META-INF/providers/'):
+            # Handles files generated by ServiceProviderProcessor
+            provider = arcname[len('META-INF/providers/'):]
+            for service in contents.strip().split(os.linesep):
+                assert service
+                self.jvmciServices.setdefault(service, []).append(provider)
+            return True
+        if arcname.endswith('_OptionDescriptors.class'):
+            # Need to create service files for the providers of the
+            # com.oracle.graal.options.Options service created by
+            # com.oracle.graal.options.processor.OptionProcessor.
+            provider = arcname[:-len('.class'):].replace('/', '.')
+            self.services.setdefault('com.oracle.graal.options.OptionDescriptors', []).append(provider)
+        return JVMCIArchiveParticipant.__add__(self, arcname, contents)
 
 def mx_post_parse_cmd_line(opts):
     add_bootclasspath_prepend(mx.distribution('truffle:TRUFFLE_API'))
--- a/mx.graal/mx_graal_9.py	Tue Jan 05 16:32:42 2016 -0800
+++ b/mx.graal/mx_graal_9.py	Tue Jan 05 16:42:05 2016 -0800
@@ -25,7 +25,7 @@
 # ----------------------------------------------------------------------------------------------------
 
 import os
-from os.path import join
+from os.path import join, exists, abspath
 from argparse import ArgumentParser
 import sanitycheck
 import re
@@ -96,13 +96,7 @@
 
 _compilers = ['graal-economy', 'graal']
 _bootClasspathDists = [
-    BootClasspathDist('GRAAL_NODEINFO'),
-    BootClasspathDist('GRAAL_API'),
-    BootClasspathDist('GRAAL_COMPILER'),
     BootClasspathDist('GRAAL'),
-    BootClasspathDist('GRAAL_HOTSPOT'),
-    BootClasspathDist('GRAAL_TRUFFLE'),
-    BootClasspathDist('GRAAL_TRUFFLE_HOTSPOT'),
 ]
 
 def add_compiler(compilerName):
@@ -182,7 +176,6 @@
 
     if args.ctwopts:
         # Replace spaces  with '#' since -G: options cannot contain spaces
-        # when they are collated in the "jvmci.options" system property
         vmargs.append('-G:CompileTheWorldConfig=' + re.sub(r'\s+', '#', args.ctwopts))
 
     if args.cp:
@@ -322,22 +315,32 @@
         if arg.startswith('-G:+'):
             if '=' in arg:
                 mx.abort('Mixing + and = in -G: option specification: ' + arg)
-            arg = '-Djvmci.option.' + arg[len('-G:+'):] + '=true'
+            arg = '-Dgraal.option.' + arg[len('-G:+'):] + '=true'
         elif arg.startswith('-G:-'):
             if '=' in arg:
                 mx.abort('Mixing - and = in -G: option specification: ' + arg)
-            arg = '-Djvmci.option.' + arg[len('-G:+'):] + '=false'
+            arg = '-Dgraal.option.' + arg[len('-G:+'):] + '=false'
         elif arg.startswith('-G:'):
-            arg = '-Djvmci.option.' + arg[len('-G:'):]
+            arg = '-Dgraal.option.' + arg[len('-G:'):]
         return arg
     args = map(translateGOption, args)
 
+    if '-G:+PrintFlags' in args and '-Xcomp' not in args:
+        mx.warn('Using -G:+PrintFlags may have no effect without -Xcomp as Graal initialization is lazy')
+
     bcp = [mx.distribution('truffle:TRUFFLE_API').classpath_repr()]
     if _jvmciModes[_vm.jvmciMode]:
         bcp.extend([d.get_classpath_repr() for d in _bootClasspathDists])
 
     args = ['-Xbootclasspath/p:' + os.pathsep.join(bcp)] + args
 
+    # Remove JVMCI from class path. It's only there to support compilation.
+    cpIndex, cp = mx.find_classpath_arg(args)
+    if cp:
+        jvmciLib = mx.library('JVMCI').path
+        cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e != jvmciLib])
+        args[cpIndex] = cp
+
     # Set the default JVMCI compiler
     jvmciCompiler = _compilers[-1]
     args = ['-Djvmci.compiler=' + jvmciCompiler] + args
@@ -389,8 +392,8 @@
         self.arc = arc
 
     def __add__(self, arcname, contents):
-        if arcname.startswith('META-INF/jvmci.providers/'):
-            provider = arcname[len('META-INF/jvmci.providers/'):]
+        if arcname.startswith('META-INF/providers/'):
+            provider = arcname[len('META-INF/providers/'):]
             for service in contents.strip().split(os.linesep):
                 assert service
                 self.services.setdefault(service, []).append(provider)
@@ -400,7 +403,7 @@
             # jdk.vm.ci.options.Options service created by
             # jdk.vm.ci.options.processor.OptionProcessor.
             provider = arcname[:-len('.class'):].replace('/', '.')
-            self.services.setdefault('jdk.vm.ci.options.OptionDescriptors', []).append(provider)
+            self.services.setdefault('com.oracle.graal.options.OptionDescriptors', []).append(provider)
         return False
 
     def __addsrc__(self, arcname, contents):
@@ -422,3 +425,69 @@
         _vm.update(opts.jvmci_mode)
     for dist in [d.dist() for d in _bootClasspathDists]:
         dist.set_archiveparticipant(GraalArchiveParticipant(dist))
+
+def _update_JVMCI_library():
+    """
+    Updates the "path" and "sha1" attributes of the "JVMCI" library to
+    refer to a jvmci.jar created from the JVMCI classes in JDK9.
+    """
+    suiteDict = _suite.suiteDict
+    jvmciLib = suiteDict['libraries']['JVMCI']
+    d = join(_suite.get_output_root(), abspath(_jdk.home)[1:])
+    path = join(d, 'jvmci.jar')
+    if not exists(path):
+        explodedModule = join(_jdk.home, 'modules', 'jdk.vm.ci')
+        if exists(explodedModule):
+            with mx.Archiver(path, kind='zip') as arc:
+                for root, _, files in os.walk(explodedModule):
+                    relpath = root[len(explodedModule) + 1:]
+                    for f in files:
+                        arcname = join(relpath, f).replace(os.sep, '/')
+                        with open(join(root, f), 'rb') as fp:
+                            contents = fp.read()
+                            arc.zf.writestr(arcname, contents)
+        else:
+            # Use the jdk.internal.jimage utility since it's the only way
+            # (currently) to read .jimage files and unfortunately the
+            # JDK9 jimage tool does not support partial extraction.
+            bootmodules = join(_jdk.home, 'lib', 'modules', 'bootmodules.jimage')
+            if not exists(bootmodules):
+                mx.abort('Could not find JVMCI classes at ' + bootmodules + ' or ' + explodedModule)
+            mx.ensure_dir_exists(d)
+            javaSource = join(d, 'ExtractJVMCI.java')
+            with open(javaSource, 'w') as fp:
+                print >> fp, """import java.io.FileOutputStream;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import jdk.internal.jimage.BasicImageReader;
+
+public class ExtractJVMCI {
+    public static void main(String[] args) throws Exception {
+        BasicImageReader image = BasicImageReader.open(args[0]);
+        String[] names = image.getEntryNames();
+        if (names.length == 0) {
+            return;
+        }
+        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(args[1]))) {
+            for (String name : names) {
+                if (name.startsWith("/jdk.vm.ci/")) {
+                    String ename = name.substring("/jdk.vm.ci/".length());
+                    JarEntry je = new JarEntry(ename);
+                    jos.putNextEntry(je);
+                    jos.write(image.getResource(name));
+                    jos.closeEntry();
+                }
+            }
+        }
+    }
+}
+"""
+            mx.run([_jdk.javac, '-d', d, javaSource])
+            mx.run([_jdk.java, '-cp', d, 'ExtractJVMCI', bootmodules, path])
+            if not exists(path):
+                mx.abort('Could not find the JVMCI classes in ' + bootmodules)
+
+    jvmciLib['path'] = path
+    jvmciLib['sha1'] = mx.sha1OfFile(path)
+
+_update_JVMCI_library()
--- a/mx.graal/suite.py	Tue Jan 05 16:32:42 2016 -0800
+++ b/mx.graal/suite.py	Tue Jan 05 16:42:05 2016 -0800
@@ -31,7 +31,7 @@
     return [s for s in l if not JDK9 or not s.get('name') == "jvmci"]
 
 suite = {
-  "mxversion" : "5.5.14",
+  "mxversion" : "5.6.7",
   "name" : "graal",
 
   "imports" : {
@@ -39,7 +39,7 @@
             {
                "name" : "jvmci",
                "optional" : "true",
-               "version" : "8c8c7e8b7ab2b19ab1949ee2e602e2067dc1e27c",
+               "version" : "f2206f5bb62ed876e9fd031f4a5a148a0cc7b57b",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -47,7 +47,7 @@
             },
             {
                "name" : "truffle",
-               "version" : "d2b4fe945c23d631fbc3aee565a08282937e3f02",
+               "version" : "d725323deb6ce02dae7d727d558813160d229d16",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/truffle", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -85,19 +85,19 @@
     },
 
     "JMH" : {
-      "sha1" : "0fe92ac8718909c632345d4ecb4e596d1fa40071",
+      "sha1" : "7e1577cf6e1f1326b78a322d206fa9412fd41ae9",
       "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/jmh/jmh-runner-1.11.2.jar"],
+      "sourceSha1" : "12a67f0dcdfe7e43218bf38c1d7fd766122a3dc7",
+      "sourceUrls" : ["https://lafo.ssw.uni-linz.ac.at/pub/jmh/jmh-runner-1.11.2-sources.jar"],
     },
 
-    # Library that allows Graal to compile against JVMCI without the jvmci suite.
-    # This library is not added to the boot class path at run time and so code
-    # compiled against this library must be run on (JVMCI enabled) JDK9.
+    # This is a library synthesized from the JVMCI classes in JDK9.
+    # It enables Graal to be compiled against JVMCI when targeting JDK8.
+    # (i.e., compiled with javac option -target 1.8).
+    # The "path" and "sha1" attributes are added when mx_graal_9 is loaded
+    # (see mx_graal_9._update_JVMCI_library()).
     "JVMCI" : {
-        "sha1" : "31c6bb33db89e7863d716641518bb6997fe2d340",
-        "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-7a570929c5e5.jar"],
-        "sourceSha1" : "8020f243ce1d5453c7a3b9f2bba52ad69ce689b4",
-        "sourceUrls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/jvmci-7a570929c5e5.src.zip"],
-        "license": "GPLv2-CPE",
+        "license" : "GPLv2-CPE",
      },
   }),
 
@@ -126,16 +126,66 @@
 
     # ------------- Graal -------------
 
+    "com.oracle.graal.serviceprovider" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : deps(["jvmci:JVMCI_SERVICES"]),
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,Graal",
+    },
+
+    "com.oracle.graal.serviceprovider.processor" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : ["com.oracle.graal.serviceprovider"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Codegen",
+    },
+
+    "com.oracle.graal.options" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "dependencies" : deps(["jvmci:JVMCI_API"]),
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "com.oracle.graal.options.processor" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.options",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Codegen",
+    },
+
+    "com.oracle.graal.options.test" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.options",
+        "mx:JUNIT",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
     "com.oracle.graal.debug" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "checkstyle" : "com.oracle.graal.graph",
       "dependencies" : deps([
         "jvmci:JVMCI_API",
+        "com.oracle.graal.options"
       ]),
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "javaCompliance" : "1.8",
-      "workingSets" : "JVMCI,Debug",
+      "workingSets" : "Graal,Debug",
     },
 
     "com.oracle.graal.debug.test" : {
@@ -147,17 +197,17 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "workingSets" : "JVMCI,Debug,Test",
+      "workingSets" : "Graal,Debug,Test",
     },
 
     "com.oracle.graal.code" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : deps([
-        "jvmci:JVMCI_SERVICE",
+        "com.oracle.graal.serviceprovider",
         "jvmci:JVMCI_API",
       ]),
-      "annotationProcessors" : deps(["jvmci:JVMCI_SERVICE_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal",
@@ -233,17 +283,34 @@
         "com.oracle.graal.code",
       ]),
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps([
+      "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
         "GRAAL_COMPILER_MATCH_PROCESSOR",
         "GRAAL_REPLACEMENTS_VERIFIER",
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
-      ]),
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,HotSpot",
     },
 
+    "com.oracle.graal.hotspot.aarch64" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.compiler.aarch64",
+        "com.oracle.graal.hotspot",
+        "com.oracle.graal.replacements.aarch64",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+        "GRAAL_NODEINFO_PROCESSOR"
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AArch64",
+    },
+
     "com.oracle.graal.hotspot.amd64" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -253,10 +320,10 @@
         "com.oracle.graal.replacements.amd64",
       ],
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
         "GRAAL_NODEINFO_PROCESSOR"
-      ]),
+      ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,HotSpot,AMD64",
     },
@@ -270,7 +337,7 @@
         "com.oracle.graal.replacements.sparc",
       ],
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps(["jvmci:JVMCI_SERVICE_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,HotSpot,SPARC",
     },
@@ -288,6 +355,19 @@
       "workingSets" : "Graal,HotSpot,Test",
     },
 
+    "com.oracle.graal.hotspot.aarch64.test" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.asm.aarch64",
+        "com.oracle.graal.hotspot.test",
+      ],
+      "annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,HotSpot,AArch64,Test",
+    },
+
     "com.oracle.graal.hotspot.amd64.test" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -329,10 +409,10 @@
         "com.oracle.graal.api.collections",
       ],
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
         "GRAAL_NODEINFO_PROCESSOR"
-      ]),
+      ],
       "workingSets" : "Graal,Graph",
     },
 
@@ -359,6 +439,17 @@
       "workingSets" : "Graal,Assembler",
     },
 
+    "com.oracle.graal.asm.aarch64" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.asm",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AArch64",
+    },
+
     "com.oracle.graal.asm.amd64" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -402,6 +493,18 @@
       "workingSets" : "Graal,Assembler,Test",
     },
 
+    "com.oracle.graal.asm.aarch64.test" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.asm.test",
+        "com.oracle.graal.asm.aarch64",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,Assembler,AArch64,Test",
+    },
+
     "com.oracle.graal.asm.amd64.test" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -421,7 +524,7 @@
         "com.oracle.graal.compiler.common",
         "com.oracle.graal.asm",
       ],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,LIR",
@@ -452,6 +555,19 @@
       "workingSets" : "Graal,LIR",
     },
 
+    "com.oracle.graal.lir.aarch64" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.lir",
+        "com.oracle.graal.asm.aarch64",
+      ],
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,LIR,AArch64",
+    },
+
     "com.oracle.graal.lir.amd64" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -459,7 +575,7 @@
         "com.oracle.graal.lir",
         "com.oracle.graal.asm.amd64",
       ],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,LIR,AMD64",
@@ -498,14 +614,30 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
         "GRAAL_REPLACEMENTS_VERIFIER",
         "GRAAL_NODEINFO_PROCESSOR",
-      ]),
+      ],
       "workingSets" : "Graal,Replacements",
     },
 
+    "com.oracle.graal.replacements.aarch64" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+          "com.oracle.graal.replacements",
+          "com.oracle.graal.lir.aarch64",
+          ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_REPLACEMENTS_VERIFIER",
+      ],
+      "workingSets" : "Graal,Replacements,AArch64",
+    },
+
     "com.oracle.graal.replacements.amd64" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -573,6 +705,7 @@
         "com.oracle.graal.lir",
         "com.oracle.graal.bytecode",
       ],
+      "generatedDependencies" : ["com.oracle.graal.serviceprovider"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "annotationProcessors" : [
@@ -595,7 +728,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : ["com.oracle.graal.nodes"],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Phases",
@@ -605,10 +738,10 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : ["com.oracle.graal.phases"],
-      "annotationProcessors" : deps([
+      "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
-        "jvmci:JVMCI_OPTIONS_PROCESSOR"
-      ]),
+        "GRAAL_OPTIONS_PROCESSOR"
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Phases",
@@ -631,10 +764,10 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : ["com.oracle.graal.phases.common"],
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
         "GRAAL_NODEINFO_PROCESSOR"
-      ]),
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Phases",
@@ -669,7 +802,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : ["com.oracle.graal.nodes"],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal",
@@ -679,10 +812,10 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-	 "com.oracle.graal.loop",
-	 "com.oracle.graal.phases.common",
+     "com.oracle.graal.loop",
+     "com.oracle.graal.phases.common",
        ],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Phases",
@@ -697,10 +830,10 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-      ]),
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+        "GRAAL_OPTIONS_PROCESSOR",
+      ],
       "workingSets" : "Graal",
     },
 
@@ -715,6 +848,36 @@
       "workingSets" : "Graal,Codegen",
     },
 
+    "com.oracle.graal.compiler.aarch64" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.compiler",
+        "com.oracle.graal.lir.aarch64",
+        "com.oracle.graal.java",
+      ],
+      "checkstyle" : "com.oracle.graal.graph",
+      "annotationProcessors" : [
+        "GRAAL_NODEINFO_PROCESSOR",
+        "GRAAL_COMPILER_MATCH_PROCESSOR",
+      ],
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AArch64",
+    },
+
+    "com.oracle.graal.compiler.aarch64.test" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : deps([
+        "com.oracle.graal.lir.jtt",
+        "com.oracle.graal.lir.aarch64",
+        "jvmci:JVMCI_HOTSPOT"
+      ]),
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal,AArch64,Test",
+    },
+
     "com.oracle.graal.compiler.amd64" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -724,10 +887,10 @@
         "com.oracle.graal.java",
       ],
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps([
+      "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
         "GRAAL_COMPILER_MATCH_PROCESSOR",
-      ]),
+      ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,AMD64",
     },
@@ -754,10 +917,10 @@
         "com.oracle.graal.java"
       ],
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps([
+      "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
         "GRAAL_COMPILER_MATCH_PROCESSOR",
-      ]),
+      ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,SPARC",
     },
@@ -789,7 +952,7 @@
       "dependencies" : [
         "com.oracle.graal.phases",
       ],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Java",
@@ -801,7 +964,7 @@
       "dependencies" : [
         "com.oracle.graal.debug",
       ],
-      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_OPTIONS_PROCESSOR"],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Java",
@@ -815,10 +978,10 @@
         "com.oracle.graal.java",
         "com.oracle.graal.compiler",
       ],
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-        "jvmci:JVMCI_SERVICE_PROCESSOR"
-      ]),
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR"
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Graph",
@@ -878,13 +1041,13 @@
         "com.oracle.graal.replacements",
       ],
       "checkstyle" : "com.oracle.graal.graph",
-      "annotationProcessors" : deps([
+      "annotationProcessors" : [
         "GRAAL_NODEINFO_PROCESSOR",
         "GRAAL_REPLACEMENTS_VERIFIER",
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
         "truffle:TRUFFLE_DSL_PROCESSOR",
-      ]),
+      ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Truffle",
       "jacoco" : "exclude",
@@ -918,10 +1081,10 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-        "jvmci:JVMCI_SERVICE_PROCESSOR"
-      ]),
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR"
+      ],
       "workingSets" : "Graal,Truffle",
     },
 
@@ -934,9 +1097,9 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
-      ]),
+      "annotationProcessors" : [
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
       "workingSets" : "Graal,Truffle",
     },
 
@@ -949,7 +1112,7 @@
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
-      "annotationProcessors" : deps(["jvmci:JVMCI_SERVICE_PROCESSOR"]),
+      "annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
       "workingSets" : "Graal,Truffle,SPARC",
     },
 
@@ -961,10 +1124,10 @@
       "dependencies" : [
         "com.oracle.graal.java",
       ],
-      "annotationProcessors" : deps([
-        "jvmci:JVMCI_OPTIONS_PROCESSOR",
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
-      ]),
+      "annotationProcessors" : [
+        "GRAAL_OPTIONS_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal",
@@ -975,6 +1138,22 @@
 
     # ------------- Distributions -------------
 
+    "GRAAL_OPTIONS" : {
+      "subDir" : "graal",
+      "dependencies" : ["com.oracle.graal.options"],
+      "distDependencies" : deps([
+        "jvmci:JVMCI_API",
+      ]),
+    },
+
+    "GRAAL_OPTIONS_PROCESSOR" : {
+      "subDir" : "graal",
+      "dependencies" : ["com.oracle.graal.options.processor"],
+      "distDependencies" : [
+        "GRAAL_OPTIONS",
+      ],
+    },
+
     "GRAAL_NODEINFO" : {
       "subDir" : "graal",
       "dependencies" : [
@@ -993,6 +1172,7 @@
       "distDependencies" : deps([
         "jvmci:JVMCI_API",
         "GRAAL_NODEINFO",
+        "GRAAL_OPTIONS",
       ]),
     },
 
@@ -1004,16 +1184,19 @@
       "exclude" : deps(["JVMCI"]),
       "distDependencies" : [
         "GRAAL_API",
+        "GRAAL_SERVICEPROVIDER",
       ],
     },
 
-    "GRAAL" : {
+    "GRAAL_RUNTIME" : {
       "subDir" : "graal",
       "dependencies" : [
         "com.oracle.graal.replacements",
         "com.oracle.graal.runtime",
         "com.oracle.graal.code",
         "com.oracle.graal.printer",
+        "com.oracle.graal.compiler.aarch64",
+        "com.oracle.graal.replacements.aarch64",
         "com.oracle.graal.compiler.amd64",
         "com.oracle.graal.replacements.amd64",
         "com.oracle.graal.compiler.sparc",
@@ -1030,6 +1213,7 @@
     "GRAAL_HOTSPOT" : {
       "subDir" : "graal",
       "dependencies" : [
+        "com.oracle.graal.hotspot.aarch64",
         "com.oracle.graal.hotspot.amd64",
         "com.oracle.graal.hotspot.sparc",
         "com.oracle.graal.hotspot",
@@ -1038,7 +1222,7 @@
       "distDependencies" : deps([
         "jvmci:JVMCI_HOTSPOT",
         "GRAAL_COMPILER",
-        "GRAAL",
+        "GRAAL_RUNTIME",
       ]),
     },
 
@@ -1047,10 +1231,14 @@
       "dependencies" : [
         "com.oracle.graal.api.test",
         "com.oracle.graal.api.directives.test",
+        "com.oracle.graal.asm.aarch64.test",
         "com.oracle.graal.asm.amd64.test",
+        "com.oracle.graal.compiler.aarch64.test",
         "com.oracle.graal.compiler.amd64.test",
         "com.oracle.graal.compiler.sparc.test",
+        "com.oracle.graal.hotspot.aarch64.test",
         "com.oracle.graal.hotspot.amd64.test",
+        "com.oracle.graal.options.test",
         "com.oracle.graal.jtt",
         "com.oracle.graal.lir.jtt",
         "com.oracle.graal.lir.test",
@@ -1074,7 +1262,7 @@
         "com.oracle.graal.truffle",
       ],
       "distDependencies" : [
-        "GRAAL",
+        "GRAAL_RUNTIME",
         "truffle:TRUFFLE_API",
       ],
     },
@@ -1104,6 +1292,23 @@
       ],
     },
 
+    "GRAAL_SERVICEPROVIDER" : {
+      "subDir" : "graal",
+      "dependencies" : ["com.oracle.graal.serviceprovider"],
+      "distDependencies" : deps([
+        "GRAAL_NODEINFO",
+        "jvmci:JVMCI_SERVICES"
+      ]),
+    },
+
+    "GRAAL_SERVICEPROVIDER_PROCESSOR" : {
+      "subDir" : "graal",
+      "dependencies" : ["com.oracle.graal.serviceprovider.processor"],
+      "distDependencies" : [
+        "GRAAL_SERVICEPROVIDER",
+      ],
+    },
+
     "GRAAL_NODEINFO_PROCESSOR" : {
       "subDir" : "graal",
       "dependencies" : ["com.oracle.graal.nodeinfo.processor"],
@@ -1117,7 +1322,8 @@
       "dependencies" : ["com.oracle.graal.replacements.verifier"],
       "distDependencies" : deps([
         "GRAAL_API",
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
       ])
     },
 
@@ -1126,8 +1332,55 @@
       "dependencies" : ["com.oracle.graal.compiler.match.processor"],
       "distDependencies" : deps([
         "GRAAL_COMPILER",
-        "jvmci:JVMCI_SERVICE_PROCESSOR",
+        "GRAAL_SERVICEPROVIDER_PROCESSOR",
       ])
     },
   },
 }
+
+if JDK9:
+    # Define a monolithic graal.jar for ease of Graal deployment without mx
+    suite["distributions"]["GRAAL"] = {
+      "subDir" : "graal",
+      "overlaps" : [
+        "GRAAL_OPTIONS",
+        "GRAAL_NODEINFO",
+        "GRAAL_API",
+        "GRAAL_COMPILER",
+        "GRAAL_RUNTIME",
+        "GRAAL_HOTSPOT",
+        "GRAAL_SERVICEPROVIDER",
+        "GRAAL_TRUFFLE",
+        "GRAAL_TRUFFLE_HOTSPOT",
+      ],
+      "dependencies" : [
+        "com.oracle.graal.options",
+        "com.oracle.graal.nodeinfo",
+        "com.oracle.graal.api.replacements",
+        "com.oracle.graal.api.runtime",
+        "com.oracle.graal.graph",
+        "com.oracle.graal.compiler",
+        "com.oracle.graal.replacements",
+        "com.oracle.graal.runtime",
+        "com.oracle.graal.code",
+        "com.oracle.graal.printer",
+        "com.oracle.graal.compiler.aarch64",
+        "com.oracle.graal.replacements.aarch64",
+        "com.oracle.graal.compiler.amd64",
+        "com.oracle.graal.replacements.amd64",
+        "com.oracle.graal.compiler.sparc",
+        "com.oracle.graal.replacements.sparc",
+        "com.oracle.graal.salver",
+        "com.oracle.graal.hotspot.aarch64",
+        "com.oracle.graal.hotspot.amd64",
+        "com.oracle.graal.hotspot.sparc",
+        "com.oracle.graal.hotspot",
+        "com.oracle.graal.truffle",
+        "com.oracle.graal.truffle.hotspot.amd64",
+        "com.oracle.graal.truffle.hotspot.sparc"
+      ],
+      "exclude" : ["JVMCI"],
+      "distDependencies" : [
+        "truffle:TRUFFLE_API",
+      ],
+    }