Mercurial > hg > graal-compiler
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<OptionValue, Object> overrides = new HashMap<>(); + * 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 && 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", + ], + }