Mercurial > hg > graal-compiler
changeset 22390:aeb7a47e272d
Merge.
author | Roland Schatz <roland.schatz@oracle.com> |
---|---|
date | Wed, 29 Jul 2015 11:59:18 +0200 |
parents | 992575891f42 (current diff) bdfd42480dc9 (diff) |
children | 1825ca1a694a |
files | graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContex.java graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContext.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSAMoveResolver.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinarScanResolveDataFlowPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScan.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSAMoveResolver.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtil.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/IndexedValueMap.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueSet.java mx.graal/mx_graal.py mx.graal/suite.py |
diffstat | 160 files changed, 7621 insertions(+), 1977 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,6 +29,9 @@ import static com.oracle.graal.asm.sparc.SPARCAssembler.Ops.*; import static java.lang.String.*; import static jdk.internal.jvmci.sparc.SPARC.*; + +import java.util.*; + import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.sparc.*; @@ -78,6 +81,10 @@ private static final Ops[] OPS; private static final Op2s[] OP2S; + private static final Op3s[][] OP3S; + + private ArrayList<Integer> delaySlotOptimizationPoints = new ArrayList<>(5); + static { Ops[] ops = Ops.values(); OPS = new Ops[ops.length]; @@ -89,6 +96,13 @@ for (Op2s op2 : op2s) { OP2S[op2.value] = op2; } + OP3S = new Op3s[2][64]; + for (Op3s op3 : Op3s.values()) { + if (op3.value >= 1 << 6) { + throw new RuntimeException("Error " + op3 + " " + op3.value); + } + OP3S[op3.op.value & 1][op3.value] = op3; + } } public enum Ops { @@ -238,7 +252,7 @@ Lddf (0b10_0011, "lddf", LdstOp), Stf (0b10_0100, "stf", LdstOp), Stfsr (0b10_0101, "stfsr", LdstOp), - Staf (0x10_0110, "staf", LdstOp), + Staf (0b10_0110, "staf", LdstOp), Stdf (0b10_0111, "stdf", LdstOp), Rd (0b10_1000, "rd", ArithOp), @@ -257,6 +271,7 @@ private final Ops op; private Op3s(int value, String name, Ops op) { + assert isImm(value, 6); this.value = value; this.operator = name; this.op = op; @@ -270,8 +285,21 @@ return operator; } - public boolean appliesTo(int instructionWord) { - return ((instructionWord >>> 19) & 0b1_1111) == value; + public boolean throwsException() { + if (op == LdstOp) { + return true; + } + switch (this) { + case Udiv: + case Udivx: + case Sdiv: + case Sdivx: + case Udivcc: + case Sdivcc: + return true; + default: + return false; + } } } @@ -796,6 +824,574 @@ } } + /** + * Specifies various bit fields used in SPARC instructions. + */ + @SuppressWarnings("unused") + public abstract static class BitSpec { + private static final BitSpec op = new ContinousBitSpec(31, 30, "op"); + private static final BitSpec op2 = new ContinousBitSpec(24, 22, "op2"); + private static final BitSpec op3 = new ContinousBitSpec(24, 19, "op3"); + private static final BitSpec rd = new ContinousBitSpec(29, 25, "rd"); + private static final BitSpec rs1 = new ContinousBitSpec(18, 14, "rs1"); + private static final BitSpec rs2 = new ContinousBitSpec(4, 0, "rs2"); + private static final BitSpec simm13 = new ContinousBitSpec(12, 0, "simm13"); + private static final BitSpec imm22 = new ContinousBitSpec(21, 0, "imm22"); + private static final BitSpec immAsi = new ContinousBitSpec(12, 5, "immASI"); + private static final BitSpec i = new ContinousBitSpec(13, 13, "i"); + private static final BitSpec disp19 = new ContinousBitSpec(18, 0, true, "disp19"); + private static final BitSpec disp22 = new ContinousBitSpec(21, 0, true, "disp22"); + private static final BitSpec disp30 = new ContinousBitSpec(29, 0, true, "disp30"); + private static final BitSpec a = new ContinousBitSpec(29, 29, "a"); + private static final BitSpec p = new ContinousBitSpec(19, 19, "p"); + private static final BitSpec cond = new ContinousBitSpec(28, 25, "cond"); + private static final BitSpec rcond = new ContinousBitSpec(27, 25, "rcond"); + private static final BitSpec cc = new ContinousBitSpec(21, 20, "cc"); + private static final BitSpec d16hi = new ContinousBitSpec(21, 20, "d16hi"); + private static final BitSpec d16lo = new ContinousBitSpec(13, 0, "d16lo"); + private static final BitSpec d16 = new CompositeBitSpec(d16hi, d16lo); + // CBCond + private static final BitSpec cLo = new ContinousBitSpec(27, 25, "cLo"); + private static final BitSpec cHi = new ContinousBitSpec(29, 29, "cHi"); + private static final BitSpec c = new CompositeBitSpec(cHi, cLo); + private static final BitSpec cbcond = new ContinousBitSpec(28, 28, "cbcond"); + private static final BitSpec cc2 = new ContinousBitSpec(21, 21, "cc2"); + private static final BitSpec d10Lo = new ContinousBitSpec(12, 5, "d10Lo"); + private static final BitSpec d10Hi = new ContinousBitSpec(20, 19, "d10Hi"); + private static final BitSpec d10 = new CompositeBitSpec(d10Hi, d10Lo); + private static final BitSpec simm5 = new ContinousBitSpec(4, 0, true, "simm5"); + + public abstract int setBits(int word, int value); + + public abstract int getBits(int word); + + public abstract int getWidth(); + + public abstract boolean valueFits(int value); + } + + public static class ContinousBitSpec extends BitSpec { + private final int hiBit; + private final int lowBit; + private final int width; + private final boolean signExt; + private final int mask; + private final String name; + + public ContinousBitSpec(int hiBit, int lowBit, String name) { + this(hiBit, lowBit, false, name); + } + + public ContinousBitSpec(int hiBit, int lowBit, boolean signExt, String name) { + super(); + this.hiBit = hiBit; + this.lowBit = lowBit; + this.signExt = signExt; + this.width = hiBit - lowBit + 1; + mask = ((1 << width) - 1) << lowBit; + this.name = name; + } + + @Override + public int setBits(int word, int value) { + assert valueFits(value) : "Value: " + value + " does not fit in " + this; + return (word & ~mask) | ((value << lowBit) & mask); + } + + @Override + public int getBits(int word) { + if (signExt) { + return ((word & mask) << (31 - hiBit)) >> (32 - width); + } else { + return (word & mask) >>> lowBit; + } + } + + @Override + public int getWidth() { + return width; + } + + @Override + public String toString() { + return String.format("%s [%d:%d]", name, hiBit, lowBit); + } + + @Override + public boolean valueFits(int value) { + if (signExt) { + return isSimm(value, getWidth()); + } else { + return isImm(value, getWidth()); + } + } + } + + public static class CompositeBitSpec extends BitSpec { + private final BitSpec left; + private final int leftWidth; + private final BitSpec right; + private final int rightWidth; + + public CompositeBitSpec(BitSpec left, BitSpec right) { + super(); + this.left = left; + this.leftWidth = left.getWidth(); + this.right = right; + this.rightWidth = right.getWidth(); + } + + @Override + public int getBits(int word) { + int l = left.getBits(word); + int r = right.getBits(word); + return l << rightWidth | r; + } + + @Override + public int setBits(int word, int value) { + int l = leftBits(value); + int r = rightBits(value); + return left.setBits(right.setBits(word, r), l); + } + + private int leftBits(int value) { + return SPARCAssembler.getBits(value, rightWidth + leftWidth, rightWidth); + } + + private int rightBits(int value) { + return SPARCAssembler.getBits(value, rightWidth - 1, 0); + } + + @Override + public int getWidth() { + return left.getWidth() + right.getWidth(); + } + + @Override + public String toString() { + return String.format("CompositeBitSpec[%s, %s]", left, right); + } + + @Override + public boolean valueFits(int value) { + return left.valueFits(leftBits(value)) && right.valueFits(rightBits(value)); + } + } + + public static class BitKey { + private final BitSpec spec; + private final int value; + + public BitKey(BitSpec spec, int value) { + super(); + this.spec = spec; + this.value = value; + } + + @Override + public String toString() { + return String.format("BitKey %s=%s", spec, value); + } + } + + /** + * Represents a prefix tree of {@link BitSpec} objects to find the most accurate SPARCOp. + */ + public static class BitKeyIndex { + private final BitSpec spec; + private final Map<Integer, BitKeyIndex> nodes; + private SPARCOp op; + + public BitKeyIndex(SPARCOp op) { + assert op != null; + this.op = op; + this.nodes = null; + this.spec = null; + } + + public BitKeyIndex(BitSpec spec) { + assert spec != null; + this.op = null; + this.nodes = new HashMap<>(4); + this.spec = spec; + } + + /** + * Adds operation to the index. + * + * @param keys Ordered by the importance + * @param operation Operation represented by this list of keys + */ + private void addOp(List<BitKey> keys, SPARCOp operation) { + assert keys.size() > 0; + BitKey first = keys.get(0); + assert first.spec.equals(spec) : first.spec + " " + spec; + BitKeyIndex node; + if (keys.size() == 1) { + if (nodes.containsKey(first.value)) { + node = nodes.get(first.value); + assert node.op == null : node + " " + keys; + node.op = operation; + } else { + assert !nodes.containsKey(first.value) : "Index must be unique. Existing key: " + nodes.get(first.value); + node = new BitKeyIndex(operation); + } + } else { + node = nodes.get(first.value); + if (node == null) { + node = new BitKeyIndex(keys.get(1).spec); + } + node.addOp(keys.subList(1, keys.size()), operation); + } + nodes.put(first.value, node); + } + + /** + * Finds the best matching {@link SPARCOp} for this instruction. + */ + public SPARCOp find(int inst) { + if (nodes != null) { + int key = spec.getBits(inst); + BitKeyIndex sub = nodes.get(key); + if (sub == null) { + if (op != null) { + return op; + } else { + throw new RuntimeException(String.format("%s 0x%x, 0x%x %s", spec, inst, key, nodes)); + } + } + return sub.find(inst); + } else { + return this.op; + } + } + + @Override + public String toString() { + return this.op == null ? this.spec + ": " + this.nodes : this.op.toString(); + } + } + + public static final Bpcc BPCC = new Bpcc(Op2s.Bp); + public static final Bpcc FBPCC = new Bpcc(Op2s.Fbp); + public static final CBCond CBCOND = new CBCond(); + public static final Bpr BPR = new Bpr(); + public static final Br BR = new Br(); + public static final Sethi SETHI = new Sethi(); + public static final Op3Op OP3 = new Op3Op(); + public static final SPARCOp LDST = new SPARCOp(Ops.LdstOp); + public static final SPARCOp BRANCH = new SPARCOp(Ops.BranchOp); + public static final SPARCOp CALL = new SPARCOp(Ops.CallOp); + private static final BitKeyIndex INDEX = new BitKeyIndex(BitSpec.op); + + static { + for (SPARCOp op : SPARCOp.OPS) { + INDEX.addOp(op.getKeys(), op); + } + } + + public static SPARCOp getSPARCOp(int inst) { + return INDEX.find(inst); + } + + /** + * Represents a class of SPARC instruction and gives methods to modify its fields. + */ + public static class SPARCOp { + private final Ops op; + private final BitKey opKey; + private List<BitKey> keyFields; + private static final List<SPARCOp> OPS = new ArrayList<>(); + + public SPARCOp(Ops op) { + super(); + this.op = op; + this.opKey = new BitKey(BitSpec.op, op.value); + OPS.add(this); + } + + protected int setBits(int word) { + return BitSpec.op.setBits(word, op.value); + } + + public boolean match(int inst) { + for (BitKey k : keyFields) { + if (k.spec.getBits(inst) != k.value) { + return false; + } + } + return true; + } + + protected List<BitKey> getKeys() { + if (keyFields == null) { + keyFields = new ArrayList<>(4); + keyFields.add(opKey); + } + return keyFields; + } + + public Ops getOp(int inst) { + return SPARCAssembler.OPS[BitSpec.op.getBits(inst)]; + } + + @Override + public String toString() { + String name = getClass().getName(); + name = name.substring(name.lastIndexOf(".") + 1); + return name + "[op: " + op + "]"; + } + } + + /** + * Base class for control transfer operations; provides access to the disp field. + */ + public abstract static class ControlTransferOp extends SPARCOp { + private final Op2s op2; + private final boolean delaySlot; + private final BitSpec disp; + private final BitKey op2Key; + + private ControlTransferOp(Ops op, Op2s op2, boolean delaySlot, BitSpec disp) { + super(op); + this.op2 = op2; + this.delaySlot = delaySlot; + this.disp = disp; + this.op2Key = new BitKey(BitSpec.op2, op2.value); + } + + public boolean hasDelaySlot() { + return delaySlot; + } + + @Override + protected int setBits(int word) { + return BitSpec.op2.setBits(super.setBits(word), op2.value); + } + + protected int setDisp(int inst, SPARCMacroAssembler masm, Label lab) { + if (lab.isBound()) { + int d = (lab.position() - masm.position()) / 4; + return setDisp(inst, d); + } else { + masm.patchUnbound(lab); + return inst; + } + } + + public int setDisp(int inst, int d) { + assert this.match(inst); + return this.disp.setBits(inst, d); + } + + public boolean isValidDisp(int d) { + return this.disp.valueFits(d); + } + + public int setAnnul(int inst, boolean a) { + return BitSpec.a.setBits(inst, a ? 1 : 0); + } + + @Override + protected List<BitKey> getKeys() { + List<BitKey> keys = super.getKeys(); + keys.add(op2Key); + return keys; + } + + public int getDisp(int inst) { + return this.disp.getBits(inst); + } + + public abstract boolean isAnnulable(int inst); + + public abstract boolean isConditional(int inst); + } + + public static class Bpcc extends ControlTransferOp { + public Bpcc(Op2s op2) { + super(Ops.BranchOp, op2, true, BitSpec.disp19); + } + + public void emit(SPARCMacroAssembler masm, CC cc, ConditionFlag cf, Annul annul, BranchPredict p, Label lab) { + int inst = setBits(0); + inst = BitSpec.a.setBits(inst, annul.flag); + inst = BitSpec.cond.setBits(inst, cf.value); + inst = BitSpec.cc.setBits(inst, cc.value); + inst = BitSpec.p.setBits(inst, p.flag); + masm.emitInt(setDisp(inst, masm, lab)); + } + + @Override + public boolean isAnnulable(int inst) { + return isConditional(inst); + } + + @Override + public boolean isConditional(int inst) { + int cond = BitSpec.cond.getBits(inst); + return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value; + } + } + + public static class Br extends ControlTransferOp { + public Br() { + super(Ops.BranchOp, Op2s.Br, true, BitSpec.disp22); + } + + @Override + public boolean isAnnulable(int inst) { + return isConditional(inst); + } + + @Override + public boolean isConditional(int inst) { + int cond = BitSpec.cond.getBits(inst); + return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value; + } + } + + public static class Bpr extends ControlTransferOp { + private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 0); + + public Bpr() { + super(Ops.BranchOp, Op2s.Bpr, true, BitSpec.d16); + } + + public void emit(SPARCMacroAssembler masm, RCondition rcond, Annul a, BranchPredict p, Register rs1, Label lab) { + int inst = setBits(0); + inst = BitSpec.rcond.setBits(inst, rcond.value); + inst = BitSpec.a.setBits(inst, a.flag); + inst = BitSpec.p.setBits(inst, p.flag); + inst = BitSpec.rs1.setBits(inst, rs1.encoding); + masm.emitInt(setDisp(inst, masm, lab)); + } + + @Override + protected List<BitKey> getKeys() { + List<BitKey> keys = super.getKeys(); + keys.add(CBCOND_KEY); + return keys; + } + + @Override + public boolean isAnnulable(int inst) { + return isConditional(inst); + } + + @Override + public boolean isConditional(int inst) { + int cond = BitSpec.cond.getBits(inst); + return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value; + } + } + + public static final class CBCond extends ControlTransferOp { + private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 1); + + private CBCond() { + super(Ops.BranchOp, Op2s.Bpr, false, BitSpec.d10); + } + + @Override + protected List<BitKey> getKeys() { + List<BitKey> keys = super.getKeys(); + keys.add(CBCOND_KEY); + return keys; + } + + public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, Register rs2, Label lab) { + int inst = setBits(0, cf, cc2, rs1); + inst = BitSpec.rs2.setBits(inst, rs2.encoding); + emit(masm, lab, inst); + } + + public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, int simm5, Label lab) { + int inst = setBits(0, cf, cc2, rs1); + inst = BitSpec.simm5.setBits(inst, simm5); + emit(masm, lab, inst); + } + + private void emit(SPARCMacroAssembler masm, Label lab, int baseInst) { + int inst = baseInst; + masm.insertNopAfterCBCond(); + masm.emitInt(setDisp(inst, masm, lab)); + } + + private int setBits(int base, ConditionFlag cf, boolean cc2, Register rs1) { + int inst = super.setBits(base); + inst = BitSpec.rs1.setBits(inst, rs1.encoding); + inst = BitSpec.cc2.setBits(inst, cc2 ? 1 : 0); + inst = BitSpec.c.setBits(inst, cf.value); + return BitSpec.cbcond.setBits(inst, 1); + } + + @Override + public boolean isAnnulable(int inst) { + return false; + } + + @Override + public boolean isConditional(int inst) { + return true; + } + } + + public static class Op2Op extends SPARCOp { + private final Op2s op2; + private final BitKey op2Key; + + public Op2Op(Ops op, Op2s op2) { + super(op); + this.op2 = op2; + op2Key = new BitKey(BitSpec.op2, op2.value); + } + + @Override + protected int setBits(int word) { + int result = super.setBits(word); + return BitSpec.op2.setBits(result, op2.value); + } + + @Override + protected List<BitKey> getKeys() { + List<BitKey> keys = super.getKeys(); + keys.add(op2Key); + return keys; + } + } + + public static class Sethi extends Op2Op { + public Sethi() { + super(Ops.BranchOp, Op2s.Sethi); + } + + public Register getRS1(int word) { + int regNum = BitSpec.rs1.getBits(word); + return SPARC.cpuRegisters[regNum]; + } + + public int getImm22(int word) { + return BitSpec.imm22.getBits(word); + } + + public boolean isNop(int inst) { + return getRS1(inst).equals(g0) && getImm22(inst) == 0; + } + } + + public static class Op3Op extends SPARCOp { + public Op3Op() { + super(ArithOp); + } + + public Op3s getOp3(int inst) { + assert match(inst); + return OP3S[ArithOp.value & 1][BitSpec.op3.getBits(inst)]; + } + } + public boolean hasFeature(CPUFeature feature) { return ((SPARC) this.target.arch).features.contains(feature); } @@ -897,7 +1493,12 @@ // @formatter:on protected void fmt00(int a, int op2, int b) { assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b); - this.emitInt(a << 25 | op2 << 22 | b); + int word = 0; + BitSpec.op.setBits(word, 0); + BitSpec.rd.setBits(word, a); + BitSpec.op2.setBits(word, op2); + BitSpec.imm22.setBits(word, b); + emitInt(a << 25 | op2 << 22 | b); } private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) { @@ -975,7 +1576,11 @@ } protected static boolean isCBCond(int inst) { - return getOp(inst).equals(Ops.BranchOp) && getOp2(inst).equals(Op2s.Bpr) && getBits(inst, 28, 28) == 1; + return isOp2(Ops.BranchOp, Op2s.Bpr, inst) && getBits(inst, 28, 28) == 1; + } + + private static boolean isOp2(Ops ops, Op2s op2s, int inst) { + return getOp(inst).equals(ops) && getOp2(inst).equals(op2s); } private static Ops getOp(int inst) { @@ -986,7 +1591,7 @@ return OP2S[getBits(inst, 24, 22)]; } - private static int getBits(int inst, int hiBit, int lowBit) { + public static int getBits(int inst, int hiBit, int lowBit) { return (inst >> lowBit) & ((1 << (hiBit - lowBit + 1)) - 1); } @@ -1033,6 +1638,7 @@ pos &= (1 << disp) - 1; int a = (annul.flag << 4) | cond.getValue(); int b = (cc.getValue() << 20) | ((predictTaken.flag) << 19) | pos; + delaySlotOptimizationPoints.add(position()); fmt00(a, op2.getValue(), b); } @@ -1055,10 +1661,11 @@ int d16hi = (pos >> 13) << 13; int d16lo = d16hi ^ pos; int b = (d16hi << 20) | (predictTaken.flag << 19) | (rs1.encoding() << 14) | d16lo; + delaySlotOptimizationPoints.add(position()); fmt00(a, Op2s.Bpr.getValue(), b); } - private int patchUnbound(Label label) { + protected int patchUnbound(Label label) { label.addPatchAt(position()); return 0; } @@ -1377,6 +1984,7 @@ public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) { int a = cc.value; int b = opf.value << 5 | rs2.encoding; + delaySlotOptimizationPoints.add(position()); fmt10(a, Fcmp.value, rs1.encoding, b); } @@ -1830,4 +2438,69 @@ public void fpadd32(Register rs1, Register rs2, Register rd) { op3(Impdep1, Fpadd32, rs1, rs2, rd); } + + /** + * Does peephole optimization on code generated by this assembler. This method should be called + * at the end of code generation. + * <p> + * It searches for conditional branch instructions which has nop in the delay slot then looks at + * the instruction at branch target; if it is an arithmetic instruction, which does not throw an + * exception (e.g. division), it pulls this instruction into the delay slot and increments the + * displacement by 1. + */ + public void peephole() { + for (int i : delaySlotOptimizationPoints) { + optimizeDelaySlot(i); + } + } + + /** + * Optimizes branch instruction <i>b</t> which has a nop in the delay slot. It tries to stuff + * the instruction at <i>b</i>s branch target into the delay slot of <i>b</i>, set the annul + * flag and increments <i>b</i>s disp field by 1; + * <p> + * If <i>b</i>s branch target instruction is an unconditional branch <i>t</i>, then it tries to + * put <i>t</i>s delayed instruction into the delay slot of <i>b</i> and add the <i>t</i>s disp + * field to <i>b</i>s disp field. + */ + private void optimizeDelaySlot(int i) { + int delaySlotAbsolute = i + INSTRUCTION_SIZE; + int nextInst = getInt(delaySlotAbsolute); + SPARCOp nextOp = getSPARCOp(nextInst); + if (nextOp instanceof Sethi && ((Sethi) nextOp).isNop(nextInst)) { + int inst = getInt(i); + SPARCOp op = getSPARCOp(inst); + if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) { + ControlTransferOp ctOp = (ControlTransferOp) op; + int disp = ctOp.getDisp(inst); + int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE; + int branchTargetInst = getInt(branchTargetAbsolute); + SPARCOp branchTargetOp = getSPARCOp(branchTargetInst); + if (branchTargetOp instanceof Op3Op) { + Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst); + if (!op3.throwsException()) { + inst = ctOp.setDisp(inst, disp + 1); // Increment the offset + inst = ctOp.setAnnul(inst, true); + emitInt(inst, i); + emitInt(branchTargetInst, delaySlotAbsolute); + } + } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) { + // If branchtarget is a unconditional branch + ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp; + int btDisp = branchTargetOpBranch.getDisp(branchTargetInst); + int newDisp = disp + btDisp; + if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size + int instAfter = ctOp.setDisp(inst, newDisp); + instAfter = ctOp.setAnnul(instAfter, true); + branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE); + branchTargetOp = getSPARCOp(branchTargetInst); + if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) { + emitInt(instAfter, i); + emitInt(branchTargetInst, delaySlotAbsolute); + } + } + } + } + } + } }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java Wed Jul 29 11:59:18 2015 +0200 @@ -76,48 +76,8 @@ protected final void patchJumpTarget(int branch, int branchTarget) { final int disp = (branchTarget - branch) / 4; final int inst = getInt(branch); - Op2s op2 = Op2s.byValue((inst & OP2_MASK) >> OP2_SHIFT); - int maskBits; - int setBits; - switch (op2) { - case Br: - case Fb: - case Sethi: - case Illtrap: - // Disp 22 in the lower 22 bits - assert isSimm(disp, 22); - setBits = disp << DISP22_SHIFT; - maskBits = DISP22_MASK; - break; - case Fbp: - case Bp: - // Disp 19 in the lower 19 bits - assert isSimm(disp, 19); - setBits = disp << DISP19_SHIFT; - maskBits = DISP19_MASK; - break; - case Bpr: - if (isCBCond(inst)) { - assert isSimm10(disp) : String.format("%d: instruction: 0x%x", disp, inst); - int d10Split = 0; - d10Split |= (disp & 0b11_0000_0000) << D10HI_SHIFT - 8; - d10Split |= (disp & 0b00_1111_1111) << D10LO_SHIFT; - setBits = d10Split; - maskBits = D10LO_MASK | D10HI_MASK; - } else { - assert isSimm(disp, 16); - int d16Split = 0; - d16Split |= (disp & 0b1100_0000_0000_0000) << D16HI_SHIFT - 14; - d16Split |= (disp & 0b0011_1111_1111_1111) << D16LO_SHIFT; - setBits = d16Split; - maskBits = D16HI_MASK | D16LO_MASK; - } - break; - default: - throw new InternalError("Unknown op2 " + op2); - } - int newInst = ~maskBits & inst; - newInst |= setBits; + ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst); + int newInst = op.setDisp(inst, disp); emitInt(newInst, branch); }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/BackendOptions.java Wed Jul 29 11:59:18 2015 +0200 @@ -25,7 +25,7 @@ import static com.oracle.graal.compiler.common.BackendOptions.UserOptions.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import jdk.internal.jvmci.options.*; -import jdk.internal.jvmci.options.DerivedOptionValue.*; +import jdk.internal.jvmci.options.DerivedOptionValue.OptionSupplier; /** * Options to control the backend configuration. @@ -36,27 +36,44 @@ // @formatter:off @Option(help = "Destruct SSA LIR eagerly (before other LIR phases).", type = OptionType.Debug) public static final OptionValue<Boolean> LIREagerSSADestruction = new OptionValue<>(false); + @Option(help = "Enable Linear Scan on SSI form.", type = OptionType.Debug) + public static final OptionValue<Boolean> LIROptSSILinearScan = new OptionValue<>(false); + @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) + public static final OptionValue<Boolean> TraceRA = new OptionValue<>(false); // @formatter:on } + /* Enable SSI Construction. */ + public static final DerivedOptionValue<Boolean> EnableSSIConstruction = new DerivedOptionValue<>(new OptionSupplier<Boolean>() { + private static final long serialVersionUID = -7375589337502162545L; + + public Boolean get() { + return LIROptSSILinearScan.getValue() || TraceRA.getValue(); + } + }); + /* Create SSA LIR during LIR generation. */ public static final DerivedOptionValue<Boolean> ConstructionSSAlirDuringLirBuilding = new DerivedOptionValue<>(new OptionSupplier<Boolean>() { private static final long serialVersionUID = 7657622005438210681L; public Boolean get() { - return SSA_LIR.getValue(); + return SSA_LIR.getValue() || EnableSSIConstruction.getValue(); } }); public enum LSRAVariant { NONSSA_LSAR, - SSA_LSRA + SSA_LSRA, + SSI_LSRA } public static final DerivedOptionValue<LSRAVariant> LinearScanVariant = new DerivedOptionValue<>(new OptionSupplier<LSRAVariant>() { private static final long serialVersionUID = 364925071685235153L; public LSRAVariant get() { + if (LIROptSSILinearScan.getValue()) { + return LSRAVariant.SSI_LSRA; + } if (SSA_LIR.getValue() && !LIREagerSSADestruction.getValue()) { return LSRAVariant.SSA_LSRA; } @@ -71,9 +88,14 @@ public Boolean get() { switch (LinearScanVariant.getValue()) { case SSA_LSRA: + case SSI_LSRA: return true; } + if (TraceRA.getValue()) { + return true; + } return false; } }); + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/TraceBuilder.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,168 @@ +/* + * 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.common.alloc; + +import java.util.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; + +public final class TraceBuilder<T extends AbstractBlockBase<T>> { + + public static final class TraceBuilderResult<T extends AbstractBlockBase<T>> { + private final List<List<T>> traces; + private final int[] blockToTrace; + + private TraceBuilderResult(List<List<T>> traces, int[] blockToTrace) { + this.traces = traces; + this.blockToTrace = blockToTrace; + } + + public int getTraceForBlock(AbstractBlockBase<?> block) { + return blockToTrace[block.getId()]; + } + + public List<List<T>> getTraces() { + return traces; + } + } + + /** + * Build traces of sequentially executed blocks. + */ + public static <T extends AbstractBlockBase<T>> TraceBuilderResult<T> computeTraces(T startBlock, List<T> blocks) { + return new TraceBuilder<>(blocks).build(startBlock); + } + + private final PriorityQueue<T> worklist; + private final BitSet processed; + /** + * Contains the number of unprocessed predecessors for every {@link AbstractBlockBase#getId() + * block}. + */ + private final int[] blocked; + private final int[] blockToTrace; + + private TraceBuilder(List<T> blocks) { + processed = new BitSet(blocks.size()); + worklist = new PriorityQueue<T>(TraceBuilder::compare); + blocked = new int[blocks.size()]; + blockToTrace = new int[blocks.size()]; + for (T block : blocks) { + blocked[block.getId()] = block.getPredecessorCount(); + } + } + + private static <T extends AbstractBlockBase<T>> int compare(T a, T b) { + return Double.compare(b.probability(), a.probability()); + } + + private boolean processed(T b) { + return processed.get(b.getId()); + } + + private TraceBuilderResult<T> build(T startBlock) { + try (Scope s = Debug.scope("TraceBuilder"); Indent i = Debug.logAndIndent("start trace building: " + startBlock)) { + ArrayList<List<T>> traces = buildTraces(startBlock); + + assert verify(traces); + return new TraceBuilderResult<>(traces, blockToTrace); + } + } + + private boolean verify(ArrayList<List<T>> traces) { + assert traces.stream().flatMap(l -> l.stream()).distinct().count() == blocked.length : "Not all blocks assigned to traces!"; + for (List<T> trace : traces) { + T last = null; + for (T current : trace) { + assert last == null || current.getPredecessors().contains(last); + last = current; + } + } + return true; + } + + protected ArrayList<List<T>> buildTraces(T startBlock) { + ArrayList<List<T>> traces = new ArrayList<>(); + // add start block + worklist.add(startBlock); + // process worklist + while (!worklist.isEmpty()) { + T block = worklist.poll(); + assert block != null; + traces.add(startTrace(block, traces.size())); + } + return traces; + } + + /** + * Build a new trace starting at {@code block}. + */ + private List<T> startTrace(T block, int traceNumber) { + assert block.getPredecessors().stream().allMatch(this::processed) : "Predecessor unscheduled: " + block.getPredecessors().stream().filter(this::processed).findFirst().get(); + ArrayList<T> trace = new ArrayList<>(); + int blockNumber = 0; + try (Indent i = Debug.logAndIndent("StartTrace: " + block)) { + for (T currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) { + Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); + processed.set(currentBlock.getId()); + worklist.remove(currentBlock); + trace.add(currentBlock); + unblock(currentBlock); + currentBlock.setLinearScanNumber(blockNumber++); + blockToTrace[currentBlock.getId()] = traceNumber; + } + } + return trace; + } + + /** + * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once + * the count reaches 0. + */ + private void unblock(T currentBlock) { + for (T successor : currentBlock.getSuccessors()) { + if (!processed(successor)) { + int blockCount = --blocked[successor.getId()]; + assert blockCount >= 0; + if (blockCount == 0) { + worklist.add(successor); + } + } + } + } + + /** + * @return The unprocessed predecessor with the highest probability, or {@code null}. + */ + private T selectNext(T currentBlock) { + T next = null; + for (T succ : currentBlock.getSuccessors()) { + if (!processed(succ) && (next == null || succ.probability() > next.probability())) { + next = succ; + } + } + return next; + } +}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/Util.java Wed Jul 29 11:59:18 2015 +0200 @@ -24,8 +24,9 @@ import java.util.*; +import com.oracle.graal.debug.*; + import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.debug.*; /** * The {@code Util} class contains a motley collection of utility methods used throughout the
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Jul 29 11:59:18 2015 +0200 @@ -64,8 +64,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.code.CallingConvention.Type; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Wed Jul 29 11:59:18 2015 +0200 @@ -24,8 +24,6 @@ import java.io.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import org.junit.*;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/LIRGenerationPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -64,7 +64,7 @@ emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap()); } context.lirGen.beforeRegisterAllocation(); - assert !ConstructionSSAlirDuringLirBuilding.getValue() || SSAUtils.verifySSAForm(lirGenRes.getLIR()); + assert !ConstructionSSAlirDuringLirBuilding.getValue() || SSAUtil.verifySSAForm(lirGenRes.getLIR()); } private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java Wed Jul 29 11:59:18 2015 +0200 @@ -23,8 +23,8 @@ package com.oracle.graal.compiler.gen; import static com.oracle.graal.compiler.gen.InstructionPrinter.InstructionLineColumn.*; -import jdk.internal.jvmci.debug.*; +import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,8 +33,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.*;
--- a/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugTimerTest.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugTimerTest.java Wed Jul 29 11:59:18 2015 +0200 @@ -26,8 +26,6 @@ import java.lang.management.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import org.junit.*;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/GraalDebugConfig.java Wed Jul 29 11:59:18 2015 +0200 @@ -199,8 +199,8 @@ * @return the {@link JavaMethod} represented by {@code context} or null */ public static JavaMethod asJavaMethod(Object context) { - if (context instanceof JavaMethodContex) { - return ((JavaMethodContex) context).asJavaMethod(); + if (context instanceof JavaMethodContext) { + return ((JavaMethodContext) context).asJavaMethod(); } return null; }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContex.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.debug; - -import jdk.internal.jvmci.meta.*; - -/** - * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a - * {@link JavaMethod}. - */ -public interface JavaMethodContex { - JavaMethod asJavaMethod(); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/JavaMethodContext.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,33 @@ +/* + * 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.debug; + +import jdk.internal.jvmci.meta.*; + +/** + * Interface for objects used in Debug {@linkplain Debug#context() context} that can provide a + * {@link JavaMethod}. + */ +public interface JavaMethodContext { + JavaMethod asJavaMethod(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/LogStream.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.debug; + +import java.io.*; + +/** + * A utility for printing compiler debug and informational output to an output stream. + * + * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying + * output stream every time one of the {@code println} methods is invoked, or a newline character ( + * {@code '\n'}) is written. + * + * All of the {@code print} and {@code println} methods return the {code LogStream} instance on + * which they were invoked. This allows chaining of these calls to mitigate use of String + * concatenation by the caller. + * + * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. Each + * line of output written to this stream has {@code n} spaces prefixed to it where {@code n} is the + * value that would be returned by {@link #indentationLevel()} when the first character of a new + * line is written. + * + * A {@code LogStream} maintains a current {@linkplain #position() position} for the current line + * being written. This position can be advanced to a specified position by + * {@linkplain #fillTo(int, char) filling} this stream with a given character. + */ +public class LogStream { + + /** + * Null output stream that simply swallows any output sent to it. + */ + public static final LogStream SINK = new LogStream(); + + private static final PrintStream SINK_PS = new PrintStream(new OutputStream() { + + @Override + public void write(int b) throws IOException { + } + }); + + private LogStream() { + this.ps = null; + this.lineBuffer = null; + } + + /** + * The output stream to which this log stream writes. + */ + private final PrintStream ps; + + private final StringBuilder lineBuffer; + private int indentationLevel; + private char indentation = ' '; + private boolean indentationDisabled; + + public final PrintStream out() { + if (ps == null) { + return SINK_PS; + } + return ps; + } + + /** + * The system dependent line separator. + */ + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** + * Creates a new log stream. + * + * @param os the underlying output stream to which prints are sent + */ + public LogStream(OutputStream os) { + ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os); + lineBuffer = new StringBuilder(100); + } + + /** + * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given + * {@link LogStream}. + * + * @param log a LogStream whose output stream is shared with this one + */ + public LogStream(LogStream log) { + ps = log.ps; + lineBuffer = new StringBuilder(100); + } + + /** + * Prepends {@link #indentation} to the current output line until its write position is equal to + * the current {@linkplain #indentationLevel()} level. + */ + private void indent() { + if (ps != null) { + if (!indentationDisabled && indentationLevel != 0) { + while (lineBuffer.length() < indentationLevel) { + lineBuffer.append(indentation); + } + } + } + } + + private LogStream flushLine(boolean withNewline) { + if (ps != null) { + if (withNewline) { + lineBuffer.append(LINE_SEPARATOR); + } + ps.print(lineBuffer.toString()); + ps.flush(); + lineBuffer.setLength(0); + } + return this; + } + + /** + * Flushes the stream. This is done by terminating the current line if it is not at position 0 + * and then flushing the underlying output stream. + */ + public void flush() { + if (ps != null) { + if (lineBuffer.length() != 0) { + flushLine(false); + } + ps.flush(); + } + } + + /** + * Gets the current column position of this log stream. + * + * @return the current column position of this log stream + */ + public int position() { + return lineBuffer == null ? 0 : lineBuffer.length(); + + } + + /** + * Gets the current indentation level for this log stream. + * + * @return the current indentation level for this log stream. + */ + public int indentationLevel() { + return indentationLevel; + } + + /** + * Adjusts the current indentation level of this log stream. + * + * @param delta + */ + public void adjustIndentation(int delta) { + if (delta < 0) { + indentationLevel = Math.max(0, indentationLevel + delta); + } else { + indentationLevel += delta; + } + } + + /** + * Gets the current indentation character of this log stream. + */ + public char indentation() { + return indentation; + } + + public void disableIndentation() { + indentationDisabled = true; + } + + public void enableIndentation() { + indentationDisabled = false; + } + + /** + * Sets the character used for indentation. + */ + public void setIndentation(char c) { + indentation = c; + } + + /** + * Advances this stream's {@linkplain #position() position} to a given position by repeatedly + * appending a given character as necessary. + * + * @param position the position to which this stream's position will be advanced + * @param filler the character used to pad the stream + */ + public LogStream fillTo(int position, char filler) { + if (ps != null) { + indent(); + while (lineBuffer.length() < position) { + lineBuffer.append(filler); + } + } + return this; + } + + /** + * Writes a boolean value to this stream as {@code "true"} or {@code "false"}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + } + return this; + } + + /** + * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + return flushLine(true); + } + return this; + } + + /** + * Writes a character value to this stream. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + if (c == '\n') { + if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) { + flushLine(false); + } + } + } + return this; + } + + /** + * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + flushLine(true); + } + return this; + } + + /** + * Prints an int value. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + } + return this; + } + + /** + * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + return flushLine(true); + } + return this; + } + + /** + * Writes a float value to this stream. + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + } + return this; + } + + /** + * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator} + * . + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + return flushLine(true); + } + return this; + } + + /** + * Writes a long value to this stream. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + } + return this; + } + + /** + * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + return flushLine(true); + } + return this; + } + + /** + * Writes a double value to this stream. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + } + return this; + } + + /** + * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + return flushLine(true); + } + return this; + } + + /** + * Writes a {@code String} value to this stream. This method ensures that the + * {@linkplain #position() position} of this stream is updated correctly with respect to any + * {@linkplain #LINE_SEPARATOR line separators} present in {@code s}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(String s) { + if (ps != null) { + if (s == null) { + indent(); + lineBuffer.append(s); + return this; + } + + int index = 0; + int next = s.indexOf(LINE_SEPARATOR, index); + while (index < s.length()) { + indent(); + if (next > index) { + lineBuffer.append(s.substring(index, next)); + flushLine(true); + index = next + LINE_SEPARATOR.length(); + next = s.indexOf(LINE_SEPARATOR, index); + } else { + lineBuffer.append(s.substring(index)); + break; + } + } + } + return this; + } + + /** + * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line + * separator}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(String s) { + if (ps != null) { + print(s); + flushLine(true); + } + return this; + } + + /** + * Writes a formatted string to this stream. + * + * @param format a format string as described in {@link String#format(String, Object...)} + * @param args the arguments to be formatted + * @return this {@link LogStream} instance + */ + public LogStream printf(String format, Object... args) { + if (ps != null) { + print(String.format(format, args)); + } + return this; + } + + /** + * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream. + * + * @return this {@code LogStream} instance + */ + public LogStream println() { + if (ps != null) { + indent(); + flushLine(true); + } + return this; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Management.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,195 @@ +/* + * 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.debug; + +import static java.lang.Thread.*; + +import java.lang.management.*; + +import javax.management.*; + +public class Management { + + private static final com.sun.management.ThreadMXBean threadMXBean = Management.initThreadMXBean(); + + /** + * The amount of memory allocated by + * {@link com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)} itself. + */ + private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes(); + + public static long getCurrentThreadAllocatedBytes() { + return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead; + } + + private static com.sun.management.ThreadMXBean initThreadMXBean() { + try { + return (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); + } catch (Error err) { + return new UnimplementedBean(); + } + } + + public static ThreadMXBean getThreadMXBean() { + return threadMXBean; + } + + private static class UnimplementedBean implements ThreadMXBean, com.sun.management.ThreadMXBean { + + public ObjectName getObjectName() { + return null; + } + + public long getThreadAllocatedBytes(long arg0) { + return 0; + } + + public long[] getThreadAllocatedBytes(long[] arg0) { + return null; + } + + public long[] getThreadCpuTime(long[] arg0) { + return null; + } + + public long[] getThreadUserTime(long[] arg0) { + return null; + } + + public boolean isThreadAllocatedMemoryEnabled() { + return false; + } + + public boolean isThreadAllocatedMemorySupported() { + return false; + } + + public void setThreadAllocatedMemoryEnabled(boolean arg0) { + } + + public int getThreadCount() { + return 0; + } + + public int getPeakThreadCount() { + return 0; + } + + public long getTotalStartedThreadCount() { + return 0; + } + + public int getDaemonThreadCount() { + return 0; + } + + public long[] getAllThreadIds() { + return null; + } + + public ThreadInfo getThreadInfo(long id) { + return null; + } + + public ThreadInfo[] getThreadInfo(long[] ids) { + return null; + } + + public ThreadInfo getThreadInfo(long id, int maxDepth) { + return null; + } + + public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) { + return null; + } + + public boolean isThreadContentionMonitoringSupported() { + return false; + } + + public boolean isThreadContentionMonitoringEnabled() { + return false; + } + + public void setThreadContentionMonitoringEnabled(boolean enable) { + } + + public long getCurrentThreadCpuTime() { + return 0; + } + + public long getCurrentThreadUserTime() { + return 0; + } + + public long getThreadCpuTime(long id) { + return 0; + } + + public long getThreadUserTime(long id) { + return 0; + } + + public boolean isThreadCpuTimeSupported() { + return false; + } + + public boolean isCurrentThreadCpuTimeSupported() { + return false; + } + + public boolean isThreadCpuTimeEnabled() { + return false; + } + + public void setThreadCpuTimeEnabled(boolean enable) { + } + + public long[] findMonitorDeadlockedThreads() { + return null; + } + + public void resetPeakThreadCount() { + } + + public long[] findDeadlockedThreads() { + return null; + } + + public boolean isObjectMonitorUsageSupported() { + return false; + } + + public boolean isSynchronizerUsageSupported() { + return false; + } + + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) { + return null; + } + + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) { + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.debug; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.regex.*; + +import jdk.internal.jvmci.service.*; + +/** + * A collection of static methods for printing debug and informational output to a global + * {@link LogStream}. The output can be (temporarily) suppressed per thread through use of a + * {@linkplain Filter filter}. + */ +public class TTY { + + /** + * Support for thread-local suppression of {@link TTY}. + */ + public static class Filter { + + private LogStream previous; + private final Thread thread = Thread.currentThread(); + + /** + * Creates an object that will suppress {@link TTY} for the current thread if the given + * filter does not match the given object. To revert the suppression state to how it was + * before this call, the {@link #remove()} method must be called on the suppression object. + * + * @param filter the pattern for matching. If {@code null}, then the match is successful. If + * it starts with "~", then a regular expression + * {@linkplain Pattern#matches(String, CharSequence) match} is performed where + * the regular expression is specified by {@code filter} without the "~" prefix. + * Otherwise, a simple {@linkplain String#contains(CharSequence) substring} match + * is performed where {@code filter} is the substring used. + * @param object an object whose {@linkplain Object#toString() string} value is matched + * against {@code filter} + */ + public Filter(String filter, Object object) { + boolean suppressed = false; + if (filter != null) { + String input = object.toString(); + if (filter.startsWith("~")) { + suppressed = !Pattern.matches(filter.substring(1), input); + } else { + suppressed = !input.contains(filter); + } + if (suppressed) { + previous = out(); + log.set(LogStream.SINK); + } + } + } + + /** + * Creates an object that will suppress {@link TTY} for the current thread. To revert the + * suppression state to how it was before this call, the {@link #remove()} method must be + * called on this filter object. + */ + public Filter() { + previous = out(); + log.set(LogStream.SINK); + } + + /** + * Reverts the suppression state of {@link TTY} to how it was before this object was + * constructed. + */ + public void remove() { + assert thread == Thread.currentThread(); + if (previous != null) { + log.set(previous); + } + } + } + + /** + * The {@link PrintStream} to which all non-suppressed output from {@link TTY} is written. + */ + public static final PrintStream out; + static { + TTYStreamProvider p = Services.loadSingle(TTYStreamProvider.class, false); + out = p == null ? System.out : p.getStream(); + } + + private static final ThreadLocal<LogStream> log = new ThreadLocal<LogStream>() { + + @Override + protected LogStream initialValue() { + return new LogStream(out); + } + }; + + public static boolean isSuppressed() { + return log.get() == LogStream.SINK; + } + + /** + * Gets the thread-local log stream to which the static methods of this class send their output. + * This will either be a global log stream or the global {@linkplain LogStream#SINK sink} + * depending on whether any suppression {@linkplain Filter filters} are in effect for the + * current thread. + */ + public static LogStream out() { + return log.get(); + } + + /** + * @see LogStream#print(String) + */ + public static void print(String s) { + out().print(s); + } + + /** + * @see LogStream#print(int) + */ + public static void print(int i) { + out().print(i); + } + + /** + * @see LogStream#print(long) + */ + public static void print(long i) { + out().print(i); + } + + /** + * @see LogStream#print(char) + */ + public static void print(char c) { + out().print(c); + } + + /** + * @see LogStream#print(boolean) + */ + public static void print(boolean b) { + out().print(b); + } + + /** + * @see LogStream#print(double) + */ + public static void print(double d) { + out().print(d); + } + + /** + * @see LogStream#print(float) + */ + public static void print(float f) { + out().print(f); + } + + /** + * @see LogStream#println(String) + */ + public static void println(String s) { + out().println(s); + } + + /** + * @see LogStream#println() + */ + public static void println() { + out().println(); + } + + /** + * @see LogStream#println(int) + */ + public static void println(int i) { + out().println(i); + } + + /** + * @see LogStream#println(long) + */ + public static void println(long l) { + out().println(l); + } + + /** + * @see LogStream#println(char) + */ + public static void println(char c) { + out().println(c); + } + + /** + * @see LogStream#println(boolean) + */ + public static void println(boolean b) { + out().println(b); + } + + /** + * @see LogStream#println(double) + */ + public static void println(double d) { + out().println(d); + } + + /** + * @see LogStream#println(float) + */ + public static void println(float f) { + out().println(f); + } + + public static void print(String format, Object... args) { + out().printf(format, args); + } + + public static void println(String format, Object... args) { + out().printf(format + "%n", args); + } + + public static void fillTo(int i) { + out().fillTo(i, ' '); + } + + public static void printFields(Class<?> javaClass) { + final String className = javaClass.getSimpleName(); + TTY.println(className + " {"); + for (final Field field : javaClass.getFields()) { + printField(field, false); + } + TTY.println("}"); + } + + public static void printField(final Field field, boolean tabbed) { + final String fieldName = String.format("%35s", field.getName()); + try { + String prefix = tabbed ? "" : " " + fieldName + " = "; + String postfix = tabbed ? "\t" : "\n"; + if (field.getType() == int.class) { + TTY.print(prefix + field.getInt(null) + postfix); + } else if (field.getType() == boolean.class) { + TTY.print(prefix + field.getBoolean(null) + postfix); + } else if (field.getType() == float.class) { + TTY.print(prefix + field.getFloat(null) + postfix); + } else if (field.getType() == String.class) { + TTY.print(prefix + field.get(null) + postfix); + } else if (field.getType() == Map.class) { + Map<?, ?> m = (Map<?, ?>) field.get(null); + TTY.print(prefix + printMap(m) + postfix); + } else { + TTY.print(prefix + field.get(null) + postfix); + } + } catch (IllegalAccessException e) { + // do nothing. + } + } + + private static String printMap(Map<?, ?> m) { + StringBuilder sb = new StringBuilder(); + + List<String> keys = new ArrayList<>(); + for (Object key : m.keySet()) { + keys.add((String) key); + } + Collections.sort(keys); + + for (String key : keys) { + sb.append(key); + sb.append("\t"); + sb.append(m.get(key)); + sb.append("\n"); + } + + return sb.toString(); + } + + public static void flush() { + out().flush(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTYStreamProvider.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,32 @@ +/* + * 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.debug; + +import java.io.*; + +/** + * Provides a {@link PrintStream} that writes to the underlying log stream of the VM. + */ +public interface TTYStreamProvider { + PrintStream getStream(); +}
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Wed Jul 29 11:59:18 2015 +0200 @@ -26,8 +26,6 @@ import java.util.*; import java.util.concurrent.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; public final class DebugScope implements Debug.Scope {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/MemUseTrackerImpl.java Wed Jul 29 11:59:18 2015 +0200 @@ -23,8 +23,6 @@ package com.oracle.graal.debug.internal; import static com.oracle.graal.debug.DebugCloseable.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; public final class MemUseTrackerImpl extends AccumulatedDebugValue implements DebugMemUseTracker {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/TimerImpl.java Wed Jul 29 11:59:18 2015 +0200 @@ -27,8 +27,6 @@ import java.lang.management.*; import java.util.concurrent.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; public final class TimerImpl extends AccumulatedDebugValue implements DebugTimer {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Wed Jul 29 11:59:18 2015 +0200 @@ -349,6 +349,7 @@ SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); } } + masm.peephole(); } private static int calculateConstantSize(LIR lir) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationStatistics.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationStatistics.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,9 +30,9 @@ import java.util.*; import java.util.concurrent.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.hotspot.*; +import com.oracle.graal.debug.*; import com.sun.management.*; @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,7 +33,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.compiler.Compiler; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.hotspot.*; import jdk.internal.jvmci.hotspot.events.*; import jdk.internal.jvmci.hotspot.events.EventProvider.CompilationEvent;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Wed Jul 29 11:59:18 2015 +0200 @@ -35,7 +35,6 @@ import java.util.stream.*; import jdk.internal.jvmci.compiler.Compiler; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.hotspot.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.options.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/DebugValuesPrinter.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,8 +30,8 @@ import java.util.stream.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; +import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Wed Jul 29 11:59:18 2015 +0200 @@ -23,9 +23,9 @@ package com.oracle.graal.hotspot; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.debug.GraalDebugConfig.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*; import static jdk.internal.jvmci.common.UnsafeAccess.*; -import static com.oracle.graal.debug.GraalDebugConfig.*; import static jdk.internal.jvmci.hotspot.InitTimer.*; import java.lang.reflect.*; @@ -34,12 +34,7 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.code.stack.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - -import com.oracle.graal.debug.*; - import jdk.internal.jvmci.hotspot.*; -import jdk.internal.jvmci.hotspot.logging.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.options.*; import jdk.internal.jvmci.runtime.*; @@ -49,8 +44,10 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.debug.*; +import com.oracle.graal.hotspot.logging.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.replacements.*; import com.oracle.graal.runtime.*;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalVMEventListener.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,12 +22,15 @@ */ package com.oracle.graal.hotspot; +import java.lang.reflect.*; +import java.util.*; + import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.hotspot.*; import jdk.internal.jvmci.service.*; import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.logging.*; @ServiceProvider(HotSpotVMEventListener.class) public class HotSpotGraalVMEventListener implements HotSpotVMEventListener { @@ -65,4 +68,36 @@ Debug.log("%s", codeCache.disassemble(installedCode)); } } + + @Override + public CompilerToVM completeInitialization(HotSpotJVMCIRuntime runtime, CompilerToVM compilerToVM) { + CompilerToVM toVM = compilerToVM; + if (CountingProxy.ENABLED) { + toVM = CountingProxy.getProxy(CompilerToVM.class, toVM); + } + if (Logger.ENABLED) { + toVM = LoggingProxy.getProxy(CompilerToVM.class, toVM); + } + + if (Boolean.valueOf(System.getProperty("jvmci.printconfig"))) { + printConfig(runtime.getConfig()); + } + + return toVM; + } + + private static void printConfig(HotSpotVMConfig config) { + Field[] fields = config.getClass().getDeclaredFields(); + Map<String, Field> sortedFields = new TreeMap<>(); + for (Field f : fields) { + f.setAccessible(true); + sortedFields.put(f.getName(), f); + } + for (Field f : sortedFields.values()) { + try { + Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config)))); + } catch (Exception e) { + } + } + } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,11 +29,10 @@ import java.util.concurrent.atomic.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import jdk.internal.jvmci.hotspot.*; import jdk.internal.jvmci.options.*; +import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.debug.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,107 @@ +/* + * 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 + * 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.logging; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +import com.oracle.graal.debug.*; + +/** + * A java.lang.reflect proxy that hierarchically logs all method invocations along with their + * parameters and return values. + */ +public class CountingProxy<T> implements InvocationHandler { + + public static final boolean ENABLED = Boolean.valueOf(System.getProperty("jvmci.countcalls")); + + private T delegate; + + private ConcurrentHashMap<Method, AtomicLong> calls = new ConcurrentHashMap<>(); + + public CountingProxy(T delegate) { + assert ENABLED; + TTY.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created"); + this.delegate = delegate; + proxies.add(this); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + int argCount = args == null ? 0 : args.length; + if (method.getParameterTypes().length != argCount) { + throw new RuntimeException("wrong parameter count"); + } + final Object result; + if (!calls.containsKey(method)) { + calls.putIfAbsent(method, new AtomicLong(0)); + } + AtomicLong count = calls.get(method); + count.incrementAndGet(); + try { + if (args == null) { + result = method.invoke(delegate); + } else { + result = method.invoke(delegate, args); + } + } catch (InvocationTargetException e) { + throw e.getCause(); + } + return result; + } + + public static <T> T getProxy(Class<T> interf, T delegate) { + Class<?>[] interfaces = ProxyUtil.getAllInterfaces(delegate.getClass()); + Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new CountingProxy<>(delegate)); + return interf.cast(obj); + } + + private static ArrayList<CountingProxy<?>> proxies = new ArrayList<>(); + + static { + if (ENABLED) { + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + for (CountingProxy<?> proxy : proxies) { + proxy.print(); + } + } + }); + } + } + + protected void print() { + long sum = 0; + for (Map.Entry<Method, AtomicLong> entry : calls.entrySet()) { + Method method = entry.getKey(); + long count = entry.getValue().get(); + sum += count; + TTY.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); + } + TTY.println(delegate.getClass().getSimpleName() + " calls: " + sum); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/HotSpotTTYStreamProvider.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,38 @@ +/* + * 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.logging; + +import java.io.*; + +import com.oracle.graal.debug.*; + +import jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import jdk.internal.jvmci.service.*; + +@ServiceProvider(TTYStreamProvider.class) +class HotSpotTTYStreamProvider implements TTYStreamProvider { + + public PrintStream getStream() { + return Options.LogFile.getStream(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,200 @@ +/* + * 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 + * 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.logging; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.debug.*; + +import jdk.internal.jvmci.hotspot.*; + +/** + * Scoped logging class used to display the call hierarchy of {@link CompilerToVM} calls. + */ +public class Logger { + + public static final boolean ENABLED = Boolean.valueOf(System.getProperty("jvmci.debug")); + private static final int SPACING = 4; + private static final ThreadLocal<Logger> loggerTL; + + private Deque<Boolean> openStack = new LinkedList<>(); + private boolean open = false; + private int level = 0; + + private static final PrintStream out; + + static { + if (ENABLED) { + loggerTL = new ThreadLocal<Logger>() { + + @Override + protected Logger initialValue() { + return new Logger(); + } + }; + } else { + loggerTL = null; + } + + PrintStream ps = null; + String filename = System.getProperty("jvmci.info_file"); + if (filename != null && !"".equals(filename)) { + try { + ps = new PrintStream(new FileOutputStream(filename)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + ps = null; + } + } + out = ps; + if (out != null) { + out.println("start: " + new Date()); + } + } + + public static void info(String message) { + if (ENABLED) { + log(message); + } else { + TTY.println(message); + } + if (out != null) { + out.println(message); + out.flush(); + } + } + + public static void log(String message) { + if (ENABLED) { + Logger logger = loggerTL.get(); + for (String line : message.split("\n")) { + if (logger.open) { + TTY.println("..."); + logger.open = false; + } + TTY.print(space(logger.level)); + TTY.println(line); + } + } + } + + public static void startScope(String message) { + if (ENABLED) { + Logger logger = loggerTL.get(); + if (logger.open) { + TTY.println("..."); + logger.open = false; + } + TTY.print(space(logger.level)); + TTY.print(message); + logger.openStack.push(logger.open); + logger.open = true; + logger.level++; + } + } + + public static void endScope(String message) { + if (ENABLED) { + Logger logger = loggerTL.get(); + logger.level--; + if (logger.open) { + TTY.println(message); + } else { + TTY.println(space(logger.level) + "..." + message); + } + logger.open = logger.openStack.pop(); + } + } + + private static String[] spaces = new String[50]; + + private static String space(int count) { + assert count >= 0; + String result; + if (count >= spaces.length || spaces[count] == null) { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < count * SPACING; i++) { + str.append(' '); + } + result = str.toString(); + if (count < spaces.length) { + spaces[count] = result; + } + } else { + result = spaces[count]; + } + return result; + } + + public static String pretty(Object value) { + if (value == null) { + return "null"; + } + + Class<?> klass = value.getClass(); + if (value instanceof Void) { + return "void"; + } else if (value instanceof String) { + return "\"" + value + "\""; + } else if (value instanceof Method) { + return "method \"" + ((Method) value).getName() + "\""; + } else if (value instanceof Class<?>) { + return "class \"" + ((Class<?>) value).getSimpleName() + "\""; + } else if (value instanceof Integer) { + if ((Integer) value < 10) { + return value.toString(); + } + return value + " (0x" + Integer.toHexString((Integer) value) + ")"; + } else if (value instanceof Long) { + if ((Long) value < 10 && (Long) value > -10) { + return value + "l"; + } + return value + "l (0x" + Long.toHexString((Long) value) + "l)"; + } else if (klass.isArray()) { + StringBuilder str = new StringBuilder(); + int dimensions = 0; + while (klass.isArray()) { + dimensions++; + klass = klass.getComponentType(); + } + int length = Array.getLength(value); + str.append(klass.getSimpleName()).append('[').append(length).append(']'); + for (int i = 1; i < dimensions; i++) { + str.append("[]"); + } + str.append(" {"); + for (int i = 0; i < length; i++) { + str.append(pretty(Array.get(value, i))); + if (i < length - 1) { + str.append(", "); + } + } + str.append('}'); + return str.toString(); + } + + return value.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/LoggingProxy.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,77 @@ +/* + * 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 + * 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.logging; + +import java.lang.reflect.*; + +/** + * A java.lang.reflect proxy that hierarchically logs all method invocations along with their + * parameters and return values. + */ +public class LoggingProxy<T> implements InvocationHandler { + + private T delegate; + + public LoggingProxy(T delegate) { + this.delegate = delegate; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + int argCount = args == null ? 0 : args.length; + if (method.getParameterTypes().length != argCount) { + throw new RuntimeException("wrong parameter count"); + } + StringBuilder str = new StringBuilder(); + str.append(method.getReturnType().getSimpleName() + " " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "("); + for (int i = 0; i < argCount; i++) { + str.append(i == 0 ? "" : ", "); + str.append(Logger.pretty(args[i])); + } + str.append(")"); + Logger.startScope(str.toString()); + final Object result; + try { + if (args == null) { + result = method.invoke(delegate); + } else { + result = method.invoke(delegate, args); + } + } catch (InvocationTargetException e) { + Logger.endScope(" = Exception " + e.getMessage()); + throw e.getCause(); + } + Logger.endScope(" = " + Logger.pretty(result)); + return result; + } + + /** + * The object returned by this method will implement all interfaces that are implemented by + * delegate. + */ + public static <T> T getProxy(Class<T> interf, T delegate) { + Class<?>[] interfaces = ProxyUtil.getAllInterfaces(delegate.getClass()); + Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new LoggingProxy<>(delegate)); + return interf.cast(obj); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/ProxyUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,46 @@ +/* + * 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 + * 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.logging; + +import java.util.*; + +public final class ProxyUtil { + + public static Class<?>[] getAllInterfaces(Class<?> clazz) { + HashSet<Class<?>> interfaces = new HashSet<>(); + getAllInterfaces(clazz, interfaces); + return interfaces.toArray(new Class<?>[interfaces.size()]); + } + + private static void getAllInterfaces(Class<?> clazz, HashSet<Class<?>> interfaces) { + for (Class<?> iface : clazz.getInterfaces()) { + if (!interfaces.contains(iface)) { + interfaces.add(iface); + getAllInterfaces(iface, interfaces); + } + } + if (clazz.getSuperclass() != null) { + getAllInterfaces(clazz.getSuperclass(), interfaces); + } + } +}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Wed Jul 29 11:59:18 2015 +0200 @@ -57,63 +57,63 @@ } } - @Snippet(removeAllFrameStates = true) + @Snippet public static boolean[] booleanArrayClone(boolean[] src) { boolean[] result = (boolean[]) NewArrayNode.newUninitializedArray(Boolean.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Boolean); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static byte[] byteArrayClone(byte[] src) { byte[] result = (byte[]) NewArrayNode.newUninitializedArray(Byte.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Byte); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static short[] shortArrayClone(short[] src) { short[] result = (short[]) NewArrayNode.newUninitializedArray(Short.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Short); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static char[] charArrayClone(char[] src) { char[] result = (char[]) NewArrayNode.newUninitializedArray(Character.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Char); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static int[] intArrayClone(int[] src) { int[] result = (int[]) NewArrayNode.newUninitializedArray(Integer.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Int); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static float[] floatArrayClone(float[] src) { float[] result = (float[]) NewArrayNode.newUninitializedArray(Float.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Float); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static long[] longArrayClone(long[] src) { long[] result = (long[]) NewArrayNode.newUninitializedArray(Long.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Long); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static double[] doubleArrayClone(double[] src) { double[] result = (double[]) NewArrayNode.newUninitializedArray(Double.TYPE, src.length); ArrayCopyCallNode.disjointArraycopy(src, 0, result, 0, src.length, Kind.Double); return result; } - @Snippet(removeAllFrameStates = true) + @Snippet public static Object[] objectArrayClone(Object[] src) { /* Since this snippet is lowered early the array must be initialized */ Object[] result = (Object[]) DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(src.getClass().getComponentType()), src.length, Kind.Object);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopySnippets.java Wed Jul 29 11:59:18 2015 +0200 @@ -464,7 +464,7 @@ /* * At least one array is of a known type requiring no store checks, so * assume the other is of the same type. Generally this is working around - * deficiencies in our propation of type information. + * deficiencies in our propagation of type information. */ componentKind = predictedKind; if (predictedKind == Kind.Object) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Jul 29 11:59:18 2015 +0200 @@ -113,7 +113,7 @@ return null; } - private class DebugScopeContext implements JavaMethod, JavaMethodContex { + private class DebugScopeContext implements JavaMethod, JavaMethodContext { public JavaMethod asJavaMethod() { return this; }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeParser.java Wed Jul 29 11:59:18 2015 +0200 @@ -38,8 +38,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; import jdk.internal.jvmci.compiler.Compiler; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,10 +22,6 @@ */ package com.oracle.graal.lir.sparc; -import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.meta.*; -import jdk.internal.jvmci.sparc.*; import static com.oracle.graal.asm.sparc.SPARCAssembler.*; import static com.oracle.graal.asm.sparc.SPARCAssembler.Annul.*; import static com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict.*; @@ -35,11 +31,15 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import static jdk.internal.jvmci.code.ValueUtil.*; import static jdk.internal.jvmci.sparc.SPARC.*; -import static jdk.internal.jvmci.sparc.SPARC.CPUFeature.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.sparc.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.gen.*; @@ -414,7 +414,7 @@ Label noOverflow = new Label(); masm.sra(asIntReg(dst), 0, tmp); masm.xorcc(SPARC.g0, SPARC.g0, SPARC.g0); - if (masm.hasFeature(CBCOND)) { + if (masm.hasFeature(SPARC.CPUFeature.CBCOND)) { masm.cbcondx(Equal, tmp, asIntReg(dst), noOverflow); // Is necessary, otherwise we will have a penalty of 5 cycles in S3 masm.nop();
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java Wed Jul 29 11:59:18 2015 +0200 @@ -41,7 +41,7 @@ @Def({REG, HINT}) protected Value result; @Use({REG}) protected Value input; @Temp({REG}) protected Value tempIndex; - @Use({STACK}) protected StackSlotValue tmpSlot; + @Use({STACK, UNINITIALIZED}) protected StackSlotValue tmpSlot; public SPARCByteSwapOp(LIRGeneratorTool tool, Value result, Value input) { super(TYPE, SIZE);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,13 +31,13 @@ import static com.oracle.graal.lir.sparc.SPARCMove.*; import static jdk.internal.jvmci.code.ValueUtil.*; import static jdk.internal.jvmci.sparc.SPARC.*; -import static jdk.internal.jvmci.sparc.SPARC.CPUFeature.*; import java.util.*; import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.sparc.*; import jdk.internal.jvmci.sparc.SPARC.CPUFeature; import com.oracle.graal.asm.*; @@ -310,12 +310,15 @@ private static boolean isShortBranch(SPARCAssembler asm, int position, LabelHint hint, Label label) { int disp = 0; + boolean dispValid = true; if (label.isBound()) { disp = label.position() - position; } else if (hint != null && hint.isValid()) { disp = hint.getTarget() - hint.getPosition(); + } else { + dispValid = false; } - if (disp != 0) { + if (dispValid) { if (disp < 0) { disp -= maximumSelfOffsetInstructions * asm.target.wordSize; } else { @@ -402,7 +405,8 @@ @Alive({REG, ILLEGAL}) protected Value constantTableBase; @Temp({REG}) protected Value scratch; private final SwitchStrategy strategy; - private final LabelHint[] labelHints; + private final Map<Label, LabelHint> labelHints; + private final List<Label> conditionalLabels = new ArrayList<>(); public StrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { super(TYPE); @@ -413,7 +417,7 @@ this.constantTableBase = constantTableBase; this.key = key; this.scratch = scratch; - this.labelHints = new LabelHint[keyTargets.length]; + this.labelHints = new HashMap<>(); assert keyConstants.length == keyTargets.length; assert keyConstants.length == strategy.keyProbabilities.length; } @@ -423,9 +427,31 @@ final Register keyRegister = asRegister(key); final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase); BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + int conditionalLabelPointer = 0; + + /** + * This method caches the generated labels over two assembly passes to get + * information about branch lengths. + */ + @Override + public Label conditionalJump(int index, Condition condition) { + Label label; + if (conditionalLabelPointer <= conditionalLabels.size()) { + label = new Label(); + conditionalLabels.add(label); + conditionalLabelPointer = conditionalLabels.size(); + } else { + // TODO: (sa) We rely here on the order how the labels are generated during + // code generation; if the order is not stable ower two assembly passes, the + // result can be wrong + label = conditionalLabels.get(conditionalLabelPointer++); + } + conditionalJump(index, condition, label); + return label; + } + @Override protected void conditionalJump(int index, Condition condition, Label target) { - requestHint(masm, index); JavaConstant constant = keyConstants[index]; CC conditionCode; Long bits; @@ -451,10 +477,15 @@ throw new JVMCIError("switch only supported for int, long and object"); } ConditionFlag conditionFlag = fromCondition(conditionCode, condition, false); - LabelHint hint = labelHints[index]; - boolean canUseShortBranch = masm.hasFeature(CBCOND) && hint.isValid() && isShortBranch(masm, masm.position(), hint, target); + LabelHint hint = requestHint(masm, target); + boolean isShortConstant = isSimm5(constant); + int cbCondPosition = masm.position(); + if (!isShortConstant) { // Load constant takes one instruction + cbCondPosition += SPARC.INSTRUCTION_SIZE; + } + boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && isShortBranch(masm, cbCondPosition, hint, target); if (bits != null && canUseShortBranch) { - if (isSimm5(constant)) { + if (isShortConstant) { if (conditionCode == Icc) { masm.cbcondw(conditionFlag, keyRegister, (int) (long) bits, target); } else { @@ -485,8 +516,13 @@ strategy.run(closure); } - private void requestHint(SPARCMacroAssembler masm, int index) { - labelHints[index] = masm.requestLabelHint(keyTargets[index].label()); + private LabelHint requestHint(SPARCMacroAssembler masm, Label label) { + LabelHint hint = labelHints.get(label); + if (hint == null) { + hint = masm.requestLabelHint(label); + labelHints.put(label, hint); + } + return hint; } @Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/GenericValueMapTest.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,78 @@ +/* + * 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.lir.test; + +import static org.junit.Assert.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.Register.RegisterCategory; +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.util.*; + +public class GenericValueMapTest { + + @Test + public void run0() { + RegisterCategory cat = new RegisterCategory("regs"); + + RegisterValue reg = new Register(0, 0, "reg0", cat).asValue(); + Variable var = new Variable(LIRKind.value(Kind.Long), 0); + Object obj0 = new Object(); + Object obj1 = new Object(); + + GenericValueMap<Object> map = new GenericValueMap<>(); + + assertNull(map.get(reg)); + assertNull(map.get(var)); + + map.put(reg, obj0); + map.put(var, obj1); + + assertEquals(obj0, map.get(reg)); + assertEquals(obj1, map.get(var)); + + map.remove(reg); + map.remove(var); + + assertNull(map.get(reg)); + assertNull(map.get(var)); + + map.put(reg, obj0); + map.put(var, obj1); + + map.put(var, obj0); + map.put(reg, obj1); + + assertEquals(obj1, map.get(reg)); + assertEquals(obj0, map.get(var)); + + map.put(reg, null); + map.put(var, null); + + assertNull(map.get(reg)); + assertNull(map.get(var)); + } +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,8 +31,8 @@ import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.dfa.*; import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.util.*; /** * This class represents garbage collection and deoptimization information attached to a LIR @@ -45,7 +45,7 @@ public final LabelRef exceptionEdge; protected DebugInfo debugInfo; - private ValueSet liveBasePointers; + private IndexedValueMap liveBasePointers; public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) { this.topFrame = topFrame; @@ -181,11 +181,11 @@ debugInfo = new DebugInfo(topFrame, virtualObjects); } - public ValueSet getLiveBasePointers() { + public IndexedValueMap getLiveBasePointers() { return liveBasePointers; } - public void setLiveBasePointers(ValueSet liveBasePointers) { + public void setLiveBasePointers(IndexedValueMap liveBasePointers) { this.liveBasePointers = liveBasePointers; }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,11 +29,10 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import jdk.internal.jvmci.meta.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; import com.oracle.graal.lir.framemap.*; @@ -132,7 +131,7 @@ assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; } if (block.getPredecessorCount() > 1) { - SSAUtils.verifyPhi(lir, block); + SSAUtil.verifyPhi(lir, block); } for (LIRInstruction op : lir.getLIRforBlock(block)) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,11 +30,10 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import jdk.internal.jvmci.meta.*; import com.oracle.graal.compiler.common.util.*; +import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; /** @@ -292,7 +291,7 @@ /** * Constants used in optimization of spilling of an interval. */ - enum SpillState { + public enum SpillState { /** * Starting state of calculation: no definition found yet. */ @@ -569,7 +568,7 @@ return kind; } - void setKind(LIRKind kind) { + public void setKind(LIRKind kind) { assert isRegister(operand) || this.kind().equals(LIRKind.Illegal) || this.kind().equals(kind) : "overwriting existing type"; this.kind = kind; } @@ -578,7 +577,7 @@ return first; } - int from() { + public int from() { return first.from; } @@ -594,11 +593,11 @@ return usePosList.size(); } - void setLocationHint(Interval interval) { + public void setLocationHint(Interval interval) { locationHint = interval; } - boolean isSplitParent() { + public boolean isSplitParent() { return splitParent == this; } @@ -647,22 +646,22 @@ return splitParent().spillState; } - int spillDefinitionPos() { + public int spillDefinitionPos() { return splitParent().spillDefinitionPos; } - void setSpillState(SpillState state) { + public void setSpillState(SpillState state) { assert state.ordinal() >= spillState().ordinal() : "state cannot decrease"; splitParent().spillState = state; } - void setSpillDefinitionPos(int pos) { - assert spillState() == SpillState.SpillInDominator || spillDefinitionPos() == -1 : "cannot set the position twice"; + public void setSpillDefinitionPos(int pos) { + assert spillState() == SpillState.SpillInDominator || spillState() == SpillState.NoDefinitionFound || spillDefinitionPos() == -1 : "cannot set the position twice"; splitParent().spillDefinitionPos = pos; } // returns true if this interval has a shadow copy on the stack that is always correct - boolean alwaysInMemory() { + public boolean alwaysInMemory() { return (splitParent().spillState == SpillState.SpillInDominator || splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory) && !canMaterialize(); } @@ -739,7 +738,7 @@ /** * Sets the value which is used for re-materialization. */ - void addMaterializationValue(JavaConstant value) { + public void addMaterializationValue(JavaConstant value) { if (numMaterializationValuesAdded == 0) { materializedValue = value; } else { @@ -1013,7 +1012,7 @@ int previousUsage(RegisterPriority minRegisterPriority, int from) { assert isVariable(operand) : "cannot access use positions for fixed intervals"; - int prev = 0; + int prev = -1; for (int i = usePosList.size() - 1; i >= 0; --i) { int usePos = usePosList.usePos(i); if (usePos > from) { @@ -1026,8 +1025,8 @@ return prev; } - void addUsePos(int pos, RegisterPriority registerPriority) { - assert covers(pos, LIRInstruction.OperandMode.USE) : "use position not covered by live range"; + public void addUsePos(int pos, RegisterPriority registerPriority) { + assert covers(pos, LIRInstruction.OperandMode.USE) : String.format("use position %d not covered by live range of interval %s", pos, this); // do not add use positions for precolored intervals because they are never used if (registerPriority != RegisterPriority.None && isVariable(operand)) { @@ -1052,7 +1051,7 @@ } } - void addRange(int from, int to) { + public void addRange(int from, int to) { assert from < to : "invalid range"; assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval"; assert from <= first().to : "not inserting at begin of interval"; @@ -1283,7 +1282,7 @@ buf.append("} uses{"); // print use positions - int prev = 0; + int prev = -1; for (int i = usePosList.size() - 1; i >= 0; --i) { assert prev < usePosList.usePos(i) : "use positions not sorted"; if (i != usePosList.size() - 1) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Wed Jul 29 11:59:18 2015 +0200 @@ -24,6 +24,7 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.lir.LIRValueUtil.*; +import static com.oracle.graal.lir.phases.LIRPhase.Options.*; import static jdk.internal.jvmci.code.CodeUtil.*; import static jdk.internal.jvmci.code.ValueUtil.*; @@ -31,13 +32,13 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.options.*; import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.lir.*; import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; @@ -53,25 +54,12 @@ * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and * Hanspeter Moessenboeck. */ -class LinearScan { - - final LIRGenerationResult res; - final LIR ir; - final FrameMapBuilder frameMapBuilder; - final RegisterAttributes[] registerAttributes; - final Register[] registers; - final RegisterAllocationConfig regAllocConfig; - private final SpillMoveFactory moveFactory; - - final boolean callKillsRegisters; - - public static final int DOMINATOR_SPILL_MOVE_ID = -2; - static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1; +public class LinearScan { public static class Options { // @formatter:off @Option(help = "Enable spill position optimization", type = OptionType.Debug) - public static final OptionValue<Boolean> LSRAOptimizeSpillPosition = new OptionValue<>(true); + public static final OptionValue<Boolean> LIROptLSRAOptimizeSpillPosition = new NestedBooleanOptionValue(LIROptimization, true); // @formatter:on } @@ -107,12 +95,22 @@ public BitSet liveKill; } + public static final int DOMINATOR_SPILL_MOVE_ID = -2; + private static final int SPLIT_INTERVALS_CAPACITY_RIGHT_SHIFT = 1; + + private final LIR ir; + private final FrameMapBuilder frameMapBuilder; + private final RegisterAttributes[] registerAttributes; + private final Register[] registers; + private final RegisterAllocationConfig regAllocConfig; + private final SpillMoveFactory moveFactory; + private final BlockMap<BlockData> blockData; /** * List of blocks in linear-scan order. This is only correct as long as the CFG does not change. */ - final List<? extends AbstractBlockBase<?>> sortedBlocks; + private final List<? extends AbstractBlockBase<?>> sortedBlocks; /** @see #intervals() */ private Interval[] intervals; @@ -152,8 +150,8 @@ */ private final int firstVariableNumber; - LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) { - this.res = res; + protected LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, + List<? extends AbstractBlockBase<?>> sortedBlocks) { this.ir = res.getLIR(); this.moveFactory = spillMoveFactory; this.frameMapBuilder = res.getFrameMapBuilder(); @@ -162,30 +160,24 @@ this.regAllocConfig = regAllocConfig; this.registers = target.arch.getRegisters(); - this.firstVariableNumber = registers.length; + this.firstVariableNumber = getRegisters().length; this.blockData = new BlockMap<>(ir.getControlFlowGraph()); - - /* - * If all allocatable registers are caller saved, then no registers are live across a call - * site. The register allocator can save time not trying to find a register at a call site. - */ - this.callKillsRegisters = regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved(); } - int getFirstLirInstructionId(AbstractBlockBase<?> block) { + public int getFirstLirInstructionId(AbstractBlockBase<?> block) { int result = ir.getLIRforBlock(block).get(0).id(); assert result >= 0; return result; } - int getLastLirInstructionId(AbstractBlockBase<?> block) { + public int getLastLirInstructionId(AbstractBlockBase<?> block) { List<LIRInstruction> instructions = ir.getLIRforBlock(block); int result = instructions.get(instructions.size() - 1).id(); assert result >= 0; return result; } - SpillMoveFactory getSpillMoveFactory() { + public SpillMoveFactory getSpillMoveFactory() { return moveFactory; } @@ -228,7 +220,7 @@ return firstVariableNumber - 1; } - BlockData getBlockData(AbstractBlockBase<?> block) { + public BlockData getBlockData(AbstractBlockBase<?> block) { return blockData.get(block); } @@ -264,7 +256,7 @@ * Gets an object describing the attributes of a given register according to this register * configuration. */ - RegisterAttributes attributes(Register reg) { + public RegisterAttributes attributes(Register reg) { return registerAttributes[reg.number]; } @@ -287,7 +279,7 @@ /** * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals. */ - Interval[] intervals() { + public Interval[] intervals() { return intervals; } @@ -334,11 +326,11 @@ } // access to block list (sorted in linear scan order) - int blockCount() { + public int blockCount() { return sortedBlocks.size(); } - AbstractBlockBase<?> blockAt(int index) { + public AbstractBlockBase<?> blockAt(int index) { return sortedBlocks.get(index); } @@ -347,7 +339,7 @@ * block. These sets do not include any operands allocated as a result of creating * {@linkplain #createDerivedInterval(Interval) derived intervals}. */ - int liveSetSize() { + public int liveSetSize() { return firstDerivedIntervalIndex == -1 ? operandSize() : firstDerivedIntervalIndex; } @@ -359,13 +351,13 @@ return intervals[operandNumber]; } - Interval intervalFor(Value operand) { + public Interval intervalFor(Value operand) { int operandNumber = operandNumber(operand); assert operandNumber < intervalsSize; return intervals[operandNumber]; } - Interval getOrCreateInterval(AllocatableValue operand) { + public Interval getOrCreateInterval(AllocatableValue operand) { Interval ret = intervalFor(operand); if (ret == null) { return createInterval(operand); @@ -407,7 +399,7 @@ * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} */ - LIRInstruction instructionForId(int opId) { + public LIRInstruction instructionForId(int opId) { assert isEven(opId) : "opId not even"; LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; assert instr.id() == opId; @@ -420,7 +412,7 @@ * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the block containing the instruction denoted by {@code opId} */ - AbstractBlockBase<?> blockForId(int opId) { + public AbstractBlockBase<?> blockForId(int opId) { assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range"; return opIdToBlockMap[opIdToIndex(opId)]; } @@ -450,7 +442,7 @@ abstract boolean apply(Interval i); } - boolean isProcessed(Value operand) { + public boolean isProcessed(Value operand) { return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable(); } @@ -515,7 +507,7 @@ return new Interval.Pair(list1, list2); } - void sortIntervalsBeforeAllocation() { + protected void sortIntervalsBeforeAllocation() { int sortedLen = 0; for (Interval interval : intervals) { if (interval != null) { @@ -585,7 +577,7 @@ // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode // instead of returning null - Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) { + public Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) { Interval result = interval.getSplitChildAtOpId(opId, mode, this); if (result != null) { @@ -622,8 +614,8 @@ return attributes(asRegister(operand)).isCallerSave(); } - <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, - RegisterAllocationConfig registerAllocationConfig) { + protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, + SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) { /* * This is the point to enable debug logging for the whole register allocation. @@ -638,7 +630,7 @@ createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); - if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) { createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); } createResolveDataFlowPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context); @@ -688,7 +680,7 @@ return new LinearScanAssignLocationsPhase(this); } - void printIntervals(String label) { + public void printIntervals(String label) { if (Debug.isLogEnabled()) { try (Indent indent = Debug.logAndIndent("intervals %s", label)) { for (Interval interval : intervals) { @@ -708,7 +700,7 @@ Debug.dump(Arrays.copyOf(intervals, intervalsSize), label); } - void printLir(String label, @SuppressWarnings("unused") boolean hirValid) { + public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) { Debug.dump(ir, label); } @@ -731,7 +723,7 @@ } } - void verifyIntervals() { + protected void verifyIntervals() { try (Indent indent = Debug.logAndIndent("verifying intervals")) { int len = intervalsSize; @@ -872,4 +864,28 @@ } } + public LIR getLIR() { + return ir; + } + + public FrameMapBuilder getFrameMapBuilder() { + return frameMapBuilder; + } + + public List<? extends AbstractBlockBase<?>> sortedBlocks() { + return sortedBlocks; + } + + public Register[] getRegisters() { + return registers; + } + + public RegisterAllocationConfig getRegisterAllocationConfig() { + return regAllocConfig; + } + + public boolean callKillsRegisters() { + return regAllocConfig.getRegisterConfig().areAllAllocatableRegistersCallerSaved(); + } + }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanAssignLocationsPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -45,7 +45,7 @@ /** * Phase 7: Assign register numbers back to LIR. */ -final class LinearScanAssignLocationsPhase extends AllocationPhase { +public final class LinearScanAssignLocationsPhase extends AllocationPhase { private final LinearScan allocator; @@ -80,7 +80,7 @@ * before the branch instruction. So the split child information for this branch * would be incorrect. */ - LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1); + LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { assert false : String.format( @@ -125,10 +125,10 @@ * is a branch, spill moves are inserted before this branch and so the wrong operand * would be returned (spill moves at block boundaries are not considered in the live * ranges of intervals). - * + * * Solution: use the first opId of the branch target block instead. */ - final LIRInstruction instr = allocator.ir.getLIRforBlock(block).get(allocator.ir.getLIRforBlock(block).size() - 1); + final LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) { tempOpId = allocator.getFirstLirInstructionId(block.getSuccessors().iterator().next()); @@ -208,9 +208,9 @@ private void assignLocations() { try (Indent indent = Debug.logAndIndent("assign locations")) { - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) { - assignLocations(allocator.ir.getLIRforBlock(block)); + assignLocations(allocator.getLIR().getLIRforBlock(block)); } } }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -42,7 +42,7 @@ import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; -class LinearScanEliminateSpillMovePhase extends AllocationPhase { +public class LinearScanEliminateSpillMovePhase extends AllocationPhase { private static final IntervalPredicate mustStoreAtDefinition = new LinearScan.IntervalPredicate() { @@ -54,7 +54,7 @@ protected final LinearScan allocator; - LinearScanEliminateSpillMovePhase(LinearScan allocator) { + protected LinearScanEliminateSpillMovePhase(LinearScan allocator) { this.allocator = allocator; } @@ -88,9 +88,9 @@ } LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { try (Indent indent1 = Debug.logAndIndent("Handle %s", block)) { - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); int numInst = instructions.size(); // iterate all instructions of the block.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -50,14 +50,14 @@ import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; -class LinearScanLifetimeAnalysisPhase extends AllocationPhase { +public class LinearScanLifetimeAnalysisPhase extends AllocationPhase { protected final LinearScan allocator; /** * @param linearScan */ - LinearScanLifetimeAnalysisPhase(LinearScan linearScan) { + protected LinearScanLifetimeAnalysisPhase(LinearScan linearScan) { allocator = linearScan; } @@ -74,7 +74,7 @@ /** * Bit set for each variable that is contained in each loop. */ - BitMap2D intervalInLoop; + private BitMap2D intervalInLoop; boolean isIntervalInLoop(int interval, int loop) { return intervalInLoop.at(interval, loop); @@ -84,7 +84,7 @@ * Numbers all instructions in all blocks. The numbering follows the * {@linkplain ComputeBlockOrder linear scan order}. */ - void numberInstructions() { + protected void numberInstructions() { allocator.initIntervals(); @@ -96,8 +96,8 @@ // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. int numInstructions = 0; - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { - numInstructions += allocator.ir.getLIRforBlock(block).size(); + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { + numInstructions += allocator.getLIR().getLIRforBlock(block).size(); } // initialize with correct length @@ -105,10 +105,10 @@ int opId = 0; int index = 0; - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { allocator.initBlockData(block); - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); int numInst = instructions.size(); for (int j = 0; j < numInst; j++) { @@ -139,13 +139,13 @@ intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops()); // iterate all blocks - for (final AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) { try (Indent indent = Debug.logAndIndent("compute local live sets for block %s", block)) { final BitSet liveGen = new BitSet(liveSize); final BitSet liveKill = new BitSet(liveSize); - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); int numInst = instructions.size(); ValueConsumer useConsumer = (operand, mode, flags) -> { @@ -249,7 +249,7 @@ * sets. This is checked by these assertions to be sure about it. The entry block may have * incoming values in registers, which is ok. */ - if (isRegister(operand) && block != allocator.ir.getControlFlowGraph().getStartBlock()) { + if (isRegister(operand) && block != allocator.getLIR().getControlFlowGraph().getStartBlock()) { if (allocator.isProcessed(operand)) { assert liveKill.get(allocator.operandNumber(operand)) : "using fixed register that is not defined in this block"; } @@ -260,7 +260,7 @@ * Performs a backward dataflow analysis to compute global live sets (i.e. * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. */ - void computeGlobalLiveSets() { + protected void computeGlobalLiveSets() { try (Indent indent = Debug.logAndIndent("compute global live sets")) { int numBlocks = allocator.blockCount(); boolean changeOccurred; @@ -313,7 +313,7 @@ /* * liveIn(block) is the union of liveGen(block) with (liveOut(block) & * !liveKill(block)). - * + * * Note: liveIn has to be computed only in first iteration or if liveOut * has changed! */ @@ -341,7 +341,7 @@ } // check that the liveIn set of the first block is empty - AbstractBlockBase<?> startBlock = allocator.ir.getControlFlowGraph().getStartBlock(); + AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock(); if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) { if (DetailedAsserts.getValue()) { reportFailure(numBlocks); @@ -352,11 +352,11 @@ } } - private void reportFailure(int numBlocks) { + protected void reportFailure(int numBlocks) { try (Scope s = Debug.forceLog()) { try (Indent indent = Debug.logAndIndent("report failure")) { - BitSet startBlockLiveIn = allocator.getBlockData(allocator.ir.getControlFlowGraph().getStartBlock()).liveIn; + BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn; try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { Interval interval = allocator.intervalFor(operandNum); @@ -382,11 +382,11 @@ Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>(); HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>(); - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { if (allocator.getBlockData(block).liveGen.get(operandNum)) { usedIn.add(block); try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { - for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) { + for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) { try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { ins.forEachState((liveStateOperand, mode, flags) -> { Debug.log("operand=%s", liveStateOperand); @@ -399,7 +399,7 @@ if (allocator.getBlockData(block).liveKill.get(operandNum)) { definedIn.add(block); try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { - for (LIRInstruction ins : allocator.ir.getLIRforBlock(block)) { + for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) { Debug.log("%d: %s", ins.id(), ins); } } @@ -436,12 +436,12 @@ } } - private void verifyLiveness() { + protected void verifyLiveness() { /* * Check that fixed intervals are not live at block boundaries (live set must be empty at * fixed intervals). */ - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { for (int j = 0; j <= allocator.maxRegisterNumber(); j++) { assert !allocator.getBlockData(block).liveIn.get(j) : "liveIn set of fixed register must be empty"; assert !allocator.getBlockData(block).liveOut.get(j) : "liveOut set of fixed register must be empty"; @@ -450,7 +450,7 @@ } } - void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { + protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { if (!allocator.isProcessed(operand)) { return; } @@ -470,7 +470,7 @@ } } - void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { + protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { if (!allocator.isProcessed(operand)) { return; } @@ -489,7 +489,7 @@ } } - void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { + protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { if (!allocator.isProcessed(operand)) { return; } @@ -520,7 +520,7 @@ } } - changeSpillDefinitionPos(interval, defPos); + changeSpillDefinitionPos(op, operand, interval, defPos); if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { // detection of method-parameters and roundfp-results interval.setSpillState(SpillState.StartInMemory); @@ -536,7 +536,7 @@ * Optimizes moves related to incoming stack based arguments. The interval for the destination * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot. */ - void handleMethodArguments(LIRInstruction op) { + protected void handleMethodArguments(LIRInstruction op) { if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; if (optimizeMethodArgument(move.getInput())) { @@ -564,7 +564,7 @@ } } - void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { + protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { if (flags.contains(OperandFlag.HINT) && LinearScan.isVariableOrRegister(targetValue)) { op.forEachRegisterHint(targetValue, mode, (registerHint, valueMode, valueFlags) -> { @@ -591,8 +591,11 @@ /** * Eliminates moves from register to stack if the stack slot is known to be correct. + * + * @param op + * @param operand */ - void changeSpillDefinitionPos(Interval interval, int defPos) { + protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) { assert interval.isSplitParent() : "can only be called for split parents"; switch (interval.spillState()) { @@ -651,7 +654,7 @@ * Determines the priority which with an instruction's input operand will be allocated a * register. */ - private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) { + protected static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) { if (flags.contains(OperandFlag.STACK)) { return RegisterPriority.ShouldHaveRegister; } @@ -659,7 +662,7 @@ return RegisterPriority.MustHaveRegister; } - void buildIntervals() { + protected void buildIntervals() { try (Indent indent = Debug.logAndIndent("build intervals")) { InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> { @@ -705,7 +708,7 @@ }; // create a list with all caller-save registers (cpu, fpu, xmm) - Register[] callerSaveRegs = allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters(); + Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters(); // iterate all blocks in reverse order for (int i = allocator.blockCount() - 1; i >= 0; i--) { @@ -713,7 +716,7 @@ AbstractBlockBase<?> block = allocator.blockAt(i); try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); final int blockFrom = allocator.getFirstLirInstructionId(block); int blockTo = allocator.getLastLirInstructionId(block); @@ -808,7 +811,7 @@ * reload-locations in case the interval of this instruction is spilled. Currently this * can only be a {@link JavaConstant}. */ - static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { + protected static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) { if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; if (move.getInput() instanceof JavaConstant) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -40,7 +40,7 @@ import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; -final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase { +public final class LinearScanOptimizeSpillPositionPhase extends AllocationPhase { private static final DebugMetric betterSpillPos = Debug.metric("BetterSpillPosition"); private static final DebugMetric betterSpillPosWithLowerProbability = Debug.metric("BetterSpillPositionWithLowerProbability"); @@ -60,7 +60,7 @@ private void optimizeSpillPosition() { try (Indent indent0 = Debug.logAndIndent("OptimizeSpillPositions")) { - LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.ir.linearScanOrder().size()]; + LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[allocator.getLIR().linearScanOrder().size()]; for (Interval interval : allocator.intervals()) { optimizeInterval(insertionBuffers, interval); } @@ -118,7 +118,7 @@ /* * The spill block is the begin of the first split child (aka the value is on the * stack). - * + * * The problem is that if spill block has more than one predecessor, the values at the * end of the predecessors might differ. Therefore, we would need a spill move in all * predecessors. To avoid this we spill in the dominator. @@ -154,7 +154,7 @@ if (insertionBuffer == null) { insertionBuffer = new LIRInsertionBuffer(); insertionBuffers[spillBlock.getId()] = insertionBuffer; - insertionBuffer.init(allocator.ir.getLIRforBlock(spillBlock)); + insertionBuffer.init(allocator.getLIR().getLIRforBlock(spillBlock)); } int spillOpId = allocator.getFirstLirInstructionId(spillBlock); // insert spill move @@ -189,8 +189,8 @@ public AbstractBlockBase<?> next() { AbstractBlockBase<?> currentBlock = block; int nextBlockIndex = block.getLinearScanNumber() + 1; - if (nextBlockIndex < allocator.sortedBlocks.size()) { - block = allocator.sortedBlocks.get(nextBlockIndex); + if (nextBlockIndex < allocator.sortedBlocks().size()) { + block = allocator.sortedBlocks().get(nextBlockIndex); if (range.to <= allocator.getFirstLirInstructionId(block)) { range = range.next; if (range == Range.EndMarker) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,8 @@ import com.oracle.graal.compiler.common.alloc.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.alloc.lsra.ssa.*; +import com.oracle.graal.lir.alloc.lsra.ssi.*; import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; @@ -42,6 +44,9 @@ RegisterAllocationConfig registerAllocationConfig) { final LinearScan allocator; switch (LinearScanVariant.getValue()) { + case SSI_LSRA: + allocator = new SSILinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder); + break; case SSA_LSRA: allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, linearScanOrder); break;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,7 +33,7 @@ import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; -final class LinearScanRegisterAllocationPhase extends AllocationPhase { +public final class LinearScanRegisterAllocationPhase extends AllocationPhase { private final LinearScan allocator;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanResolveDataFlowPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -41,11 +41,11 @@ * * Insert moves at edges between blocks if intervals have been split. */ -class LinearScanResolveDataFlowPhase extends AllocationPhase { +public class LinearScanResolveDataFlowPhase extends AllocationPhase { protected final LinearScan allocator; - LinearScanResolveDataFlowPhase(LinearScan allocator) { + protected LinearScanResolveDataFlowPhase(LinearScan allocator) { this.allocator = allocator; } @@ -55,7 +55,7 @@ resolveDataFlow(); } - void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { + protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { assert moveResolver.checkEmpty(); assert midBlock == null || (midBlock.getPredecessorCount() == 1 && midBlock.getSuccessorCount() == 1 && midBlock.getPredecessors().get(0).equals(fromBlock) && midBlock.getSuccessors().get(0).equals( @@ -87,7 +87,7 @@ Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId()); } - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(fromBlock); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(fromBlock); LIRInstruction instr = instructions.get(instructions.size() - 1); if (instr instanceof StandardOp.JumpOp) { // insert moves before branch @@ -102,7 +102,7 @@ } if (DetailedAsserts.getValue()) { - assert allocator.ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; + assert allocator.getLIR().getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; /* * Because the number of predecessor edges matches the number of successor edges, @@ -114,7 +114,7 @@ } } - moveResolver.setInsertPosition(allocator.ir.getLIRforBlock(toBlock), 1); + moveResolver.setInsertPosition(allocator.getLIR().getLIRforBlock(toBlock), 1); } } @@ -122,7 +122,7 @@ * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that * have been split. */ - void resolveDataFlow() { + protected void resolveDataFlow() { try (Indent indent = Debug.logAndIndent("resolve data flow")) { MoveResolver moveResolver = allocator.createMoveResolver(); @@ -136,11 +136,11 @@ } protected void optimizeEmptyBlocks(MoveResolver moveResolver, BitSet blockCompleted) { - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { // check if block has only one predecessor and only one successor if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; @@ -174,7 +174,7 @@ protected void resolveDataFlow0(MoveResolver moveResolver, BitSet blockCompleted) { BitSet alreadyResolved = new BitSet(allocator.blockCount()); - for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks) { + for (AbstractBlockBase<?> fromBlock : allocator.sortedBlocks()) { if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { alreadyResolved.clear(); alreadyResolved.or(blockCompleted);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java Wed Jul 29 11:59:18 2015 +0200 @@ -84,12 +84,12 @@ super(allocator, unhandledFixedFirst, unhandledAnyFirst); moveResolver = allocator.createMoveResolver(); - spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]); - for (int i = 0; i < allocator.registers.length; i++) { + spillIntervals = Util.uncheckedCast(new List[allocator.getRegisters().length]); + for (int i = 0; i < allocator.getRegisters().length; i++) { spillIntervals[i] = EMPTY_LIST; } - usePos = new int[allocator.registers.length]; - blockPos = new int[allocator.registers.length]; + usePos = new int[allocator.getRegisters().length]; + blockPos = new int[allocator.getRegisters().length]; } void initUseLists(boolean onlyProcessUsePos) { @@ -268,7 +268,7 @@ // numbering of instructions is known. // When the block already contains spill moves, the index must be increased until the // correct index is reached. - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(opBlock); + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(opBlock); int index = (opId - instructions.get(0).id()) >> 1; assert instructions.get(index).id() <= opId : "error in calculation"; @@ -509,7 +509,8 @@ try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) { - assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; + assert interval.firstUsage(RegisterPriority.MustHaveRegister) > currentPosition : String.format("interval %s must not have use position before currentPosition %d", interval, + currentPosition); allocator.assignSpillSlot(interval); handleSpillSlot(interval); @@ -593,7 +594,7 @@ * The loop depth of the spilling position is higher then the loop depth at the * definition of the interval. Move write to memory out of loop. */ - if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) { // find best spill position in dominator the tree interval.setSpillState(SpillState.SpillInDominator); } else { @@ -611,7 +612,7 @@ } case OneSpillStore: { - if (LinearScan.Options.LSRAOptimizeSpillPosition.getValue()) { + if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) { // the interval is spilled more then once interval.setSpillState(SpillState.SpillInDominator); } else { @@ -785,7 +786,7 @@ int firstShouldHaveUsage = interval.firstUsage(RegisterPriority.ShouldHaveRegister); int regNeededUntil = Math.min(firstUsage, interval.from() + 1); int intervalTo = interval.to(); - assert regNeededUntil > 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use"; + assert regNeededUntil >= 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use"; Register reg; Register ignore; @@ -845,7 +846,7 @@ * errors */ allocator.assignSpillSlot(interval); - Debug.dump(allocator.ir, description); + Debug.dump(allocator.getLIR(), description); allocator.printIntervals(description); throw new OutOfRegistersException("LinearScan: no register found", description); } @@ -892,7 +893,7 @@ } boolean noAllocationPossible(Interval interval) { - if (allocator.callKillsRegisters) { + if (allocator.callKillsRegisters()) { // fast calculation of intervals that can never get a register because the // the next instruction is a call that blocks all registers // Note: this only works if a call kills all registers @@ -917,7 +918,7 @@ } void initVarsForAlloc(Interval interval) { - AllocatableRegisters allocatableRegisters = allocator.regAllocConfig.getAllocatableRegisters(interval.kind().getPlatformKind()); + AllocatableRegisters allocatableRegisters = allocator.getRegisterAllocationConfig().getAllocatableRegisters(interval.kind().getPlatformKind()); availableRegs = allocatableRegisters.allocatableRegisters; minReg = allocatableRegisters.minRegisterNumber; maxReg = allocatableRegisters.maxRegisterNumber;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java Wed Jul 29 11:59:18 2015 +0200 @@ -36,14 +36,14 @@ /** */ -class MoveResolver { +public class MoveResolver { private final LinearScan allocator; private int insertIdx; private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted - protected final List<Interval> mappingFrom; + private final List<Interval> mappingFrom; private final List<Value> mappingFromOpr; private final List<Interval> mappingTo; private boolean multipleReadsAllowed; @@ -58,6 +58,14 @@ } } + protected Interval getMappingFrom(int i) { + return mappingFrom.get(i); + } + + protected int mappingFromSize() { + return mappingFrom.size(); + } + protected int valueBlocked(Value location) { if (isRegister(location)) { return registerBlocked[asRegister(location).number]; @@ -81,7 +89,7 @@ return allocator; } - MoveResolver(LinearScan allocator) { + protected MoveResolver(LinearScan allocator) { this.allocator = allocator; this.multipleReadsAllowed = false; @@ -90,12 +98,12 @@ this.mappingTo = new ArrayList<>(8); this.insertIdx = -1; this.insertionBuffer = new LIRInsertionBuffer(); - this.registerBlocked = new int[allocator.registers.length]; + this.registerBlocked = new int[allocator.getRegisters().length]; } - boolean checkEmpty() { + protected boolean checkEmpty() { assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing"; - for (int i = 0; i < getAllocator().registers.length; i++) { + for (int i = 0; i < getAllocator().getRegisters().length; i++) { assert registerBlocked[i] == 0 : "register map must be empty before and after processing"; } checkMultipleReads(); @@ -351,7 +359,7 @@ // one stack slot to another can happen (not allowed by LIRAssembler StackSlotValue spillSlot = fromInterval.spillSlot(); if (spillSlot == null) { - spillSlot = getAllocator().frameMapBuilder.allocateSpillSlot(fromInterval.kind()); + spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind()); fromInterval.setSpillSlot(spillSlot); } spillInterval(spillCandidate, fromInterval, spillSlot); @@ -420,7 +428,7 @@ this.insertIdx = newInsertIdx; } - void addMapping(Interval fromInterval, Interval toInterval) { + public void addMapping(Interval fromInterval, Interval toInterval) { if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) { if (Debug.isLogEnabled()) { @@ -446,7 +454,7 @@ mappingTo.add(toInterval); } - void addMapping(Value fromOpr, Interval toInterval) { + public void addMapping(Value fromOpr, Interval toInterval) { if (Debug.isLogEnabled()) { Debug.log("add move mapping from %s to %s", fromOpr, toInterval); }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java Wed Jul 29 11:59:18 2015 +0200 @@ -74,7 +74,7 @@ @Override void walk() { try (Scope s = Debug.scope("OptimizingLinearScanWalker")) { - for (AbstractBlockBase<?> block : allocator.sortedBlocks) { + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { optimizeBlock(block); } }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java Wed Jul 29 11:59:18 2015 +0200 @@ -120,7 +120,7 @@ protected void printState(Interval[] inputState) { for (int i = 0; i < stateSize(); i++) { - Register reg = allocator.registers[i]; + Register reg = allocator.getRegisters()[i]; assert reg.number == i; if (inputState[i] != null) { Debug.log(" %6s %4d -- %s", reg, inputState[i].operandNumber, inputState[i]); @@ -202,7 +202,7 @@ } void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) { - List<LIRInstruction> ops = allocator.ir.getLIRforBlock(block); + List<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block); InstructionValueConsumer useConsumer = new InstructionValueConsumer() { @Override @@ -242,7 +242,7 @@ op.visitEachInput(useConsumer); // invalidate all caller save registers at calls if (op.destroysCallerSavedRegisters()) { - for (Register r : allocator.regAllocConfig.getRegisterConfig().getCallerSaveRegisters()) { + for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) { statePut(inputState, r.asValue(), null); } }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinarScanResolveDataFlowPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * 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.lir.alloc.lsra; - -import static jdk.internal.jvmci.code.ValueUtil.*; - -import java.util.*; - -import com.oracle.graal.debug.*; -import jdk.internal.jvmci.meta.*; - -import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.ssa.*; -import com.oracle.graal.lir.ssa.SSAUtils.PhiValueVisitor; - -class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase { - - private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]"); - private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]"); - - SSALinarScanResolveDataFlowPhase(LinearScan allocator) { - super(allocator); - } - - @Override - void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { - super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); - - if (toBlock.getPredecessorCount() > 1) { - int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock); - int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1; - - AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock; - List<LIRInstruction> instructions = allocator.ir.getLIRforBlock(phiOutBlock); - int phiOutIdx = SSAUtils.phiOutIndex(allocator.ir, phiOutBlock); - int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id(); - assert phiOutId >= 0; - - PhiValueVisitor visitor = new PhiValueVisitor() { - - public void visit(Value phiIn, Value phiOut) { - assert !isRegister(phiOut) : "phiOut is a register: " + phiOut; - assert !isRegister(phiIn) : "phiIn is a register: " + phiIn; - Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); - if (isConstant(phiOut)) { - numPhiResolutionMoves.increment(); - moveResolver.addMapping(phiOut, toInterval); - } else { - Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF); - if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { - numPhiResolutionMoves.increment(); - if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { - moveResolver.addMapping(fromInterval, toInterval); - } else { - numStackToStackMoves.increment(); - moveResolver.addMapping(fromInterval, toInterval); - } - } - } - } - }; - - SSAUtils.forEachPhiValuePair(allocator.ir, toBlock, phiOutBlock, visitor); - SSAUtils.removePhiOut(allocator.ir, phiOutBlock); - } - } - -}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScan.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * 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.lir.alloc.lsra; - -import java.util.*; - -import jdk.internal.jvmci.code.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.*; - -import com.oracle.graal.compiler.common.alloc.*; -import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.lir.gen.*; -import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; -import com.oracle.graal.lir.ssa.*; - -final class SSALinearScan extends LinearScan { - - SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, List<? extends AbstractBlockBase<?>> sortedBlocks) { - super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks); - } - - @Override - protected MoveResolver createMoveResolver() { - SSAMoveResolver moveResolver = new SSAMoveResolver(this); - assert moveResolver.checkEmpty(); - return moveResolver; - } - - @Override - protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { - return new SSALinearScanLifetimeAnalysisPhase(this); - } - - @Override - protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { - return new SSALinarScanResolveDataFlowPhase(this); - } - - @Override - protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { - return new SSALinearScanEliminateSpillMovePhase(this); - } - - @Override - protected void beforeSpillMoveElimination() { - /* - * PHI Ins are needed for the RegisterVerifier, otherwise PHIs where the Out and In value - * matches (ie. there is no resolution move) are falsely detected as errors. - */ - try (Scope s1 = Debug.scope("Remove Phi In")) { - for (AbstractBlockBase<?> toBlock : sortedBlocks) { - if (toBlock.getPredecessorCount() > 1) { - SSAUtils.removePhiIn(ir, toBlock); - } - } - } - } - -}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanEliminateSpillMovePhase.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * 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.lir.alloc.lsra; - -import static com.oracle.graal.compiler.common.BackendOptions.*; -import static com.oracle.graal.lir.LIRValueUtil.*; -import static jdk.internal.jvmci.code.ValueUtil.*; -import com.oracle.graal.debug.*; - -import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.LabelOp; -import com.oracle.graal.lir.StandardOp.MoveOp; - -public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase { - - SSALinearScanEliminateSpillMovePhase(LinearScan allocator) { - super(allocator); - } - - @Override - protected int firstInstructionOfInterest() { - // also look at Labels as they define PHI values - return 0; - } - - @Override - protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) { - assert isVariable(move.getResult()) || LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA : "Move should not be produced in a non-SSA compilation: " + move; - - if (super.canEliminateSpillMove(block, move)) { - // SSA Linear Scan might introduce moves to stack slots - Interval curInterval = allocator.intervalFor(move.getResult()); - assert !isRegister(curInterval.location()) && curInterval.alwaysInMemory(); - if (!isPhiResolutionMove(block, move, curInterval)) { - assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); - return true; - } - } - return false; - } - - private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) { - assert LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA; - if (!toInterval.isSplitParent()) { - return false; - } - if ((toInterval.from() & 1) == 1) { - // phi intervals start at even positions. - return false; - } - if (block.getSuccessorCount() != 1) { - return false; - } - LIRInstruction op = allocator.instructionForId(toInterval.from()); - if (!(op instanceof LabelOp)) { - return false; - } - AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from()); - assert allocator.ir.getLIRforBlock(intStartBlock).get(0).equals(op); - if (!block.getSuccessors().get(0).equals(intStartBlock)) { - return false; - } - try (Indent indet = Debug.indent()) { - Debug.log("Is a move (%s) to phi interval %s", move, toInterval); - } - return true; - } -}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSALinearScanLifetimeAnalysisPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * 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.lir.alloc.lsra; - -import java.util.*; - -import com.oracle.graal.debug.*; -import jdk.internal.jvmci.meta.*; - -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.OperandFlag; -import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.StandardOp.LabelOp; -import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; -import com.oracle.graal.lir.ssa.*; - -public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase { - - SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) { - super(linearScan); - } - - @Override - void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { - super.addRegisterHint(op, targetValue, mode, flags, hintAtDef); - - if (hintAtDef && op instanceof LabelOp) { - LabelOp label = (LabelOp) op; - - Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); - - SSAUtils.forEachPhiRegisterHint(allocator.ir, allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> { - if (LinearScan.isVariableOrRegister(registerHint)) { - Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); - - setHint(op, to, from); - setHint(op, from, to); - } - }); - } - } - - private static void setHint(final LIRInstruction op, Interval target, Interval source) { - Interval currentHint = target.locationHint(false); - if (currentHint == null || currentHint.from() > target.from()) { - /* - * Update hint if there was none or if the hint interval starts after the hinted - * interval. - */ - target.setLocationHint(source); - if (Debug.isLogEnabled()) { - Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber); - } - } - } - - @Override - protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { - if (op instanceof LabelOp) { - LabelOp label = (LabelOp) op; - if (label.isPhiIn()) { - return RegisterPriority.None; - } - } - return super.registerPriorityOfOutputOperand(op); - } -}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/SSAMoveResolver.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * 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.lir.alloc.lsra; - -import static jdk.internal.jvmci.code.ValueUtil.*; - -import java.util.*; - -import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.meta.*; - -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.framemap.*; - -final class SSAMoveResolver extends MoveResolver { - - private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1; - private int[] stackBlocked; - private final int firstVirtualStackIndex; - - SSAMoveResolver(LinearScan allocator) { - super(allocator); - FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.frameMapBuilder; - FrameMap frameMap = frameMapBuilderTool.getFrameMap(); - this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()]; - this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1; - } - - @Override - boolean checkEmpty() { - for (int i = 0; i < stackBlocked.length; i++) { - assert stackBlocked[i] == 0 : "stack map must be empty before and after processing"; - } - return super.checkEmpty(); - } - - @Override - protected void checkMultipleReads() { - // multiple reads are allowed in SSA LSRA - } - - @Override - protected void verifyStackSlotMapping() { - // relax disjoint stack maps invariant - } - - @Override - protected boolean areMultipleReadsAllowed() { - return true; - } - - @Override - protected boolean mightBeBlocked(Value location) { - if (super.mightBeBlocked(location)) { - return true; - } - if (isStackSlotValue(location)) { - return true; - } - return false; - } - - private int getStackArrayIndex(StackSlotValue stackSlotValue) { - if (isStackSlot(stackSlotValue)) { - return getStackArrayIndex(asStackSlot(stackSlotValue)); - } - if (isVirtualStackSlot(stackSlotValue)) { - return getStackArrayIndex(asVirtualStackSlot(stackSlotValue)); - } - throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue); - } - - private int getStackArrayIndex(StackSlot stackSlot) { - int stackIdx; - if (stackSlot.isInCallerFrame()) { - // incoming stack arguments can be ignored - stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX; - } else { - assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot; - int offset = -stackSlot.getRawOffset(); - assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex); - stackIdx = offset; - } - return stackIdx; - } - - private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) { - return firstVirtualStackIndex + virtualStackSlot.getId(); - } - - @Override - protected void setValueBlocked(Value location, int direction) { - assert direction == 1 || direction == -1 : "out of bounds"; - if (isStackSlotValue(location)) { - int stackIdx = getStackArrayIndex(asStackSlotValue(location)); - if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { - // incoming stack arguments can be ignored - return; - } - if (stackIdx >= stackBlocked.length) { - stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1); - } - stackBlocked[stackIdx] += direction; - } else { - super.setValueBlocked(location, direction); - } - } - - @Override - protected int valueBlocked(Value location) { - if (isStackSlotValue(location)) { - int stackIdx = getStackArrayIndex(asStackSlotValue(location)); - if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { - // incoming stack arguments are always blocked (aka they can not be written) - return 1; - } - if (stackIdx >= stackBlocked.length) { - return 0; - } - return stackBlocked[stackIdx]; - } - return super.valueBlocked(location); - } - - @Override - protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) { - if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) { - return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr); - } - return super.createMove(fromOpr, toOpr, fromLocation, toLocation); - } - - @Override - protected void breakCycle(int spillCandidate) { - if (spillCandidate != -1) { - super.breakCycle(spillCandidate); - return; - } - assert mappingFrom.size() > 1; - // Arbitrarily select the first entry for spilling. - int stackSpillCandidate = 0; - Interval fromInterval = mappingFrom.get(stackSpillCandidate); - assert isStackSlotValue(fromInterval.location()); - // allocate new stack slot - StackSlotValue spillSlot = getAllocator().frameMapBuilder.allocateSpillSlot(fromInterval.kind()); - spillInterval(stackSpillCandidate, fromInterval, spillSlot); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinarScanResolveDataFlowPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,91 @@ +/* + * 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.lir.alloc.lsra.ssa; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.debug.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.ssa.*; +import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor; + +class SSALinarScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase { + + private static final DebugMetric numPhiResolutionMoves = Debug.metric("SSA LSRA[numPhiResolutionMoves]"); + private static final DebugMetric numStackToStackMoves = Debug.metric("SSA LSRA[numStackToStackMoves]"); + + SSALinarScanResolveDataFlowPhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { + super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); + + if (toBlock.getPredecessorCount() > 1) { + int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock); + int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1; + + AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock; + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(phiOutBlock); + int phiOutIdx = SSAUtil.phiOutIndex(allocator.getLIR(), phiOutBlock); + int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id(); + assert phiOutId >= 0; + + PhiValueVisitor visitor = new PhiValueVisitor() { + + public void visit(Value phiIn, Value phiOut) { + assert !isRegister(phiOut) : "phiOut is a register: " + phiOut; + assert !isRegister(phiIn) : "phiIn is a register: " + phiIn; + Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF); + if (isConstant(phiOut)) { + numPhiResolutionMoves.increment(); + moveResolver.addMapping(phiOut, toInterval); + } else { + Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF); + if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) { + numPhiResolutionMoves.increment(); + if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { + moveResolver.addMapping(fromInterval, toInterval); + } else { + numStackToStackMoves.increment(); + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + } + }; + + SSAUtil.forEachPhiValuePair(allocator.getLIR(), toBlock, phiOutBlock, visitor); + SSAUtil.removePhiOut(allocator.getLIR(), phiOutBlock); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScan.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,82 @@ +/* + * 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.lir.alloc.lsra.ssa; + +import java.util.*; + +import jdk.internal.jvmci.code.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.ssa.*; + +public final class SSALinearScan extends LinearScan { + + public SSALinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, + List<? extends AbstractBlockBase<?>> sortedBlocks) { + super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks); + } + + @Override + protected MoveResolver createMoveResolver() { + SSAMoveResolver moveResolver = new SSAMoveResolver(this); + assert moveResolver.checkEmpty(); + return moveResolver; + } + + @Override + protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { + return new SSALinearScanLifetimeAnalysisPhase(this); + } + + @Override + protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { + return new SSALinarScanResolveDataFlowPhase(this); + } + + @Override + protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { + return new SSALinearScanEliminateSpillMovePhase(this); + } + + @Override + protected void beforeSpillMoveElimination() { + /* + * PHI Ins are needed for the RegisterVerifier, otherwise PHIs where the Out and In value + * matches (ie. there is no resolution move) are falsely detected as errors. + */ + try (Scope s1 = Debug.scope("Remove Phi In")) { + for (AbstractBlockBase<?> toBlock : sortedBlocks()) { + if (toBlock.getPredecessorCount() > 1) { + SSAUtil.removePhiIn(getLIR(), toBlock); + } + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanEliminateSpillMovePhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,90 @@ +/* + * 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.lir.alloc.lsra.ssa; + +import static com.oracle.graal.compiler.common.BackendOptions.*; +import static com.oracle.graal.lir.LIRValueUtil.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.alloc.lsra.*; + +public class SSALinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase { + + SSALinearScanEliminateSpillMovePhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected int firstInstructionOfInterest() { + // also look at Labels as they define PHI values + return 0; + } + + @Override + protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) { + assert isVariable(move.getResult()) || LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA : "Move should not be produced in a non-SSA compilation: " + move; + + if (super.canEliminateSpillMove(block, move)) { + // SSA Linear Scan might introduce moves to stack slots + Interval curInterval = allocator.intervalFor(move.getResult()); + assert !isRegister(curInterval.location()) && curInterval.alwaysInMemory(); + if (!isPhiResolutionMove(block, move, curInterval)) { + assert isStackSlotValue(curInterval.location()) : "Not a stack slot: " + curInterval.location(); + return true; + } + } + return false; + } + + private boolean isPhiResolutionMove(AbstractBlockBase<?> block, MoveOp move, Interval toInterval) { + assert LinearScanVariant.getValue() == LSRAVariant.SSA_LSRA; + if (!toInterval.isSplitParent()) { + return false; + } + if ((toInterval.from() & 1) == 1) { + // phi intervals start at even positions. + return false; + } + if (block.getSuccessorCount() != 1) { + return false; + } + LIRInstruction op = allocator.instructionForId(toInterval.from()); + if (!(op instanceof LabelOp)) { + return false; + } + AbstractBlockBase<?> intStartBlock = allocator.blockForId(toInterval.from()); + assert allocator.getLIR().getLIRforBlock(intStartBlock).get(0).equals(op); + if (!block.getSuccessors().get(0).equals(intStartBlock)) { + return false; + } + try (Indent indet = Debug.indent()) { + Debug.log("Is a move (%s) to phi interval %s", move, toInterval); + } + return true; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSALinearScanLifetimeAnalysisPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,89 @@ +/* + * 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.lir.alloc.lsra.ssa; + +import java.util.*; + +import com.oracle.graal.debug.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; +import com.oracle.graal.lir.ssa.*; + +public class SSALinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase { + + SSALinearScanLifetimeAnalysisPhase(LinearScan linearScan) { + super(linearScan); + } + + @Override + protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { + super.addRegisterHint(op, targetValue, mode, flags, hintAtDef); + + if (hintAtDef && op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + + Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); + + SSAUtil.forEachPhiRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> { + if (LinearScan.isVariableOrRegister(registerHint)) { + Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); + + setHint(op, to, from); + setHint(op, from, to); + } + }); + } + } + + public static void setHint(final LIRInstruction op, Interval target, Interval source) { + Interval currentHint = target.locationHint(false); + if (currentHint == null || currentHint.from() > target.from()) { + /* + * Update hint if there was none or if the hint interval starts after the hinted + * interval. + */ + target.setLocationHint(source); + if (Debug.isLogEnabled()) { + Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), source.operandNumber, target.operandNumber); + } + } + } + + @Override + protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { + if (op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + if (label.isPhiIn()) { + return RegisterPriority.None; + } + } + return super.registerPriorityOfOutputOperand(op); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssa/SSAMoveResolver.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,170 @@ +/* + * 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.lir.alloc.lsra.ssa; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.framemap.*; + +public final class SSAMoveResolver extends MoveResolver { + + private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1; + private int[] stackBlocked; + private final int firstVirtualStackIndex; + + public SSAMoveResolver(LinearScan allocator) { + super(allocator); + FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) allocator.getFrameMapBuilder(); + FrameMap frameMap = frameMapBuilderTool.getFrameMap(); + this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()]; + this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1; + } + + @Override + public boolean checkEmpty() { + for (int i = 0; i < stackBlocked.length; i++) { + assert stackBlocked[i] == 0 : "stack map must be empty before and after processing"; + } + return super.checkEmpty(); + } + + @Override + protected void checkMultipleReads() { + // multiple reads are allowed in SSA LSRA + } + + @Override + protected void verifyStackSlotMapping() { + // relax disjoint stack maps invariant + } + + @Override + protected boolean areMultipleReadsAllowed() { + return true; + } + + @Override + protected boolean mightBeBlocked(Value location) { + if (super.mightBeBlocked(location)) { + return true; + } + if (isStackSlotValue(location)) { + return true; + } + return false; + } + + private int getStackArrayIndex(StackSlotValue stackSlotValue) { + if (isStackSlot(stackSlotValue)) { + return getStackArrayIndex(asStackSlot(stackSlotValue)); + } + if (isVirtualStackSlot(stackSlotValue)) { + return getStackArrayIndex(asVirtualStackSlot(stackSlotValue)); + } + throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue); + } + + private int getStackArrayIndex(StackSlot stackSlot) { + int stackIdx; + if (stackSlot.isInCallerFrame()) { + // incoming stack arguments can be ignored + stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX; + } else { + assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot; + int offset = -stackSlot.getRawOffset(); + assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex); + stackIdx = offset; + } + return stackIdx; + } + + private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) { + return firstVirtualStackIndex + virtualStackSlot.getId(); + } + + @Override + protected void setValueBlocked(Value location, int direction) { + assert direction == 1 || direction == -1 : "out of bounds"; + if (isStackSlotValue(location)) { + int stackIdx = getStackArrayIndex(asStackSlotValue(location)); + if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { + // incoming stack arguments can be ignored + return; + } + if (stackIdx >= stackBlocked.length) { + stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1); + } + stackBlocked[stackIdx] += direction; + } else { + super.setValueBlocked(location, direction); + } + } + + @Override + protected int valueBlocked(Value location) { + if (isStackSlotValue(location)) { + int stackIdx = getStackArrayIndex(asStackSlotValue(location)); + if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { + // incoming stack arguments are always blocked (aka they can not be written) + return 1; + } + if (stackIdx >= stackBlocked.length) { + return 0; + } + return stackBlocked[stackIdx]; + } + return super.valueBlocked(location); + } + + @Override + protected LIRInstruction createMove(AllocatableValue fromOpr, AllocatableValue toOpr, AllocatableValue fromLocation, AllocatableValue toLocation) { + if (isStackSlotValue(toLocation) && isStackSlotValue(fromLocation)) { + return getAllocator().getSpillMoveFactory().createStackMove(toOpr, fromOpr); + } + return super.createMove(fromOpr, toOpr, fromLocation, toLocation); + } + + @Override + protected void breakCycle(int spillCandidate) { + if (spillCandidate != -1) { + super.breakCycle(spillCandidate); + return; + } + assert mappingFromSize() > 1; + // Arbitrarily select the first entry for spilling. + int stackSpillCandidate = 0; + Interval fromInterval = getMappingFrom(stackSpillCandidate); + assert isStackSlotValue(fromInterval.location()); + // allocate new stack slot + StackSlotValue spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind()); + spillInterval(stackSpillCandidate, fromInterval, spillSlot); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScan.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,72 @@ +/* + * 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.lir.alloc.lsra.ssi; + +import java.util.*; + +import jdk.internal.jvmci.code.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.ssa.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.ssi.*; + +public final class SSILinearScan extends LinearScan { + + public SSILinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, + List<? extends AbstractBlockBase<?>> sortedBlocks) { + super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks); + } + + @Override + protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, + SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) { + assert SSIVerifier.verify(lirGenRes.getLIR()) : "LIR not in SSI form."; + super.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig); + } + + @Override + protected MoveResolver createMoveResolver() { + SSAMoveResolver moveResolver = new SSAMoveResolver(this); + assert moveResolver.checkEmpty(); + return moveResolver; + } + + @Override + protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { + return new SSILinearScanLifetimeAnalysisPhase(this); + } + + @Override + protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { + return new SSILinearScanResolveDataFlowPhase(this); + } + + @Override + protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { + return new SSILinearScanEliminateSpillMovePhase(this); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanEliminateSpillMovePhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,46 @@ +/* + * 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.lir.alloc.lsra.ssi; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.alloc.lsra.*; + +public class SSILinearScanEliminateSpillMovePhase extends LinearScanEliminateSpillMovePhase { + + public SSILinearScanEliminateSpillMovePhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected int firstInstructionOfInterest() { + // also look at Labels as they define PHI values + return 0; + } + + @Override + protected boolean canEliminateSpillMove(AbstractBlockBase<?> block, MoveOp move) { + // TODO (je) do not eliminate spill moves yet! + return false; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanLifetimeAnalysisPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,123 @@ +/* + * 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.lir.alloc.lsra.ssi; + +import static com.oracle.graal.lir.alloc.lsra.ssa.SSALinearScanLifetimeAnalysisPhase.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; +import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; +import com.oracle.graal.lir.ssi.*; + +public class SSILinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase { + + public SSILinearScanLifetimeAnalysisPhase(LinearScan linearScan) { + super(linearScan); + } + + @Override + protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) { + super.addRegisterHint(op, targetValue, mode, flags, hintAtDef); + + if (hintAtDef && op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + + Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue); + + SSIUtil.forEachRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> { + if (LinearScan.isVariableOrRegister(registerHint)) { + Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint); + + setHint(op, to, from); + setHint(op, from, to); + } + }); + } + } + + @Override + protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) { + assert interval.isSplitParent() : "can only be called for split parents"; + + switch (interval.spillState()) { + case NoDefinitionFound: + // assert interval.spillDefinitionPos() == -1 : "must no be set before"; + interval.setSpillDefinitionPos(defPos); + if (!(op instanceof LabelOp)) { + // Do not update state for labels. This will be done afterwards. + interval.setSpillState(SpillState.NoSpillStore); + } + break; + + case NoSpillStore: + assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; + if (defPos < interval.spillDefinitionPos() - 2) { + // second definition found, so no spill optimization possible for this interval + interval.setSpillState(SpillState.NoOptimization); + } else { + // two consecutive definitions (because of two-operand LIR form) + assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal"; + } + break; + + case NoOptimization: + // nothing to do + break; + + default: + throw new BailoutException("other states not allowed at this time"); + } + } + + @Override + protected void buildIntervals() { + super.buildIntervals(); + for (Interval interval : allocator.intervals()) { + if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) { + // there was a definition in a phi/sigma + interval.setSpillState(SpillState.NoSpillStore); + } + } + } + + @Override + protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { + if (op instanceof LabelOp) { + LabelOp label = (LabelOp) op; + if (label.id() != 0) { + // skip method header + return RegisterPriority.None; + } + } + return super.registerPriorityOfOutputOperand(op); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/ssi/SSILinearScanResolveDataFlowPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,128 @@ +/* + * 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.lir.alloc.lsra.ssi; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor; +import com.oracle.graal.lir.ssi.*; + +public class SSILinearScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase { + + private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]"); + private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]"); + + public SSILinearScanResolveDataFlowPhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected void resolveDataFlow() { + super.resolveDataFlow(); + /* + * Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the Out + * and In value matches (ie. there is no resolution move) are falsely detected as errors. + */ + for (AbstractBlockBase<?> toBlock : allocator.sortedBlocks()) { + if (toBlock.getPredecessorCount() != 0) { + SSIUtil.removeIncoming(allocator.getLIR(), toBlock); + } else { + assert allocator.getLIR().getControlFlowGraph().getStartBlock().equals(toBlock); + } + SSIUtil.removeOutgoing(allocator.getLIR(), toBlock); + } + } + + @Override + protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { + super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); + + if (midBlock != null) { + HashMap<Value, Value> map = CollectionsFactory.newMap(); + SSIUtil.forEachValuePair(allocator.getLIR(), midBlock, fromBlock, (to, from) -> map.put(to, from)); + + MyPhiValueVisitor visitor = new MyPhiValueVisitor(moveResolver, toBlock, fromBlock); + SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, midBlock, (to, from) -> { + Value phiOut = isConstant(from) ? from : map.get(from); + assert phiOut != null : "No entry for " + from; + visitor.visit(to, phiOut); + }); + } else { + // default case + SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock)); + } + + } + + private class MyPhiValueVisitor implements PhiValueVisitor { + final MoveResolver moveResolver; + final int toId; + final int fromId; + + public MyPhiValueVisitor(MoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) { + this.moveResolver = moveResolver; + toId = allocator.getFirstLirInstructionId(toBlock); + fromId = allocator.getLastLirInstructionId(fromBlock); + assert fromId >= 0; + } + + public void visit(Value phiIn, Value phiOut) { + assert !isRegister(phiOut) : "Out is a register: " + phiOut; + assert !isRegister(phiIn) : "In is a register: " + phiIn; + if (Value.ILLEGAL.equals(phiIn)) { + // The value not needed in this branch. + return; + } + if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) { + // no need to handle virtual stack slots + return; + } + Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF); + if (isConstant(phiOut)) { + numSSIResolutionMoves.increment(); + moveResolver.addMapping(phiOut, toInterval); + } else { + Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF); + if (fromInterval != toInterval) { + numSSIResolutionMoves.increment(); + if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { + moveResolver.addMapping(fromInterval, toInterval); + } else { + numStackToStackMoves.increment(); + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,96 @@ +/* + * 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.lir.alloc.trace; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor; +import com.oracle.graal.lir.ssi.*; + +public class TraceGlobalMoveResolutionPhase extends AllocationPhase { + + private final TraceBuilderResult<?> resultTraces; + + public TraceGlobalMoveResolutionPhase(TraceBuilderResult<?> resultTraces) { + this.resultTraces = resultTraces; + } + + @Override + protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + resolveGlobalDataFlow(resultTraces, lirGenRes, spillMoveFactory, target.arch); + } + + private static <B extends AbstractBlockBase<B>> void resolveGlobalDataFlow(TraceBuilderResult<B> resultTraces, LIRGenerationResult lirGenRes, SpillMoveFactory spillMoveFactory, Architecture arch) { + LIR lir = lirGenRes.getLIR(); + /* Resolve trace global data-flow mismatch. */ + TraceGlobalMoveResolver moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, arch); + PhiValueVisitor visitor = (Value phiIn, Value phiOut) -> { + if (!isIllegal(phiIn) && !TraceGlobalMoveResolver.isMoveToSelf(phiOut, phiIn)) { + moveResolver.addMapping(phiOut, (AllocatableValue) phiIn); + } + }; + + try (Indent indent = Debug.logAndIndent("Trace global move resolution")) { + for (List<B> trace : resultTraces.getTraces()) { + for (AbstractBlockBase<?> fromBlock : trace) { + for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) { + if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) { + try (Indent indent0 = Debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock), toBlock, + resultTraces.getTraceForBlock(toBlock))) { + + final List<LIRInstruction> instructions; + final int insertIdx; + if (fromBlock.getSuccessorCount() == 1) { + instructions = lir.getLIRforBlock(fromBlock); + insertIdx = instructions.size() - 1; + } else { + assert toBlock.getPredecessorCount() == 1; + instructions = lir.getLIRforBlock(toBlock); + insertIdx = 1; + } + + moveResolver.setInsertPosition(instructions, insertIdx); + SSIUtil.forEachValuePair(lir, toBlock, fromBlock, visitor); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceGlobalMoveResolver.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2009, 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.lir.alloc.trace; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; + +/** + */ +class TraceGlobalMoveResolver { + + private int insertIdx; + private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted + + private final List<Value> mappingFrom; + private final List<AllocatableValue> mappingTo; + private final int[] registerBlocked; + private static final int STACK_SLOT_IN_CALLER_FRAME_IDX = -1; + private int[] stackBlocked; + private final int firstVirtualStackIndex; + private final SpillMoveFactory spillMoveFactory; + private final FrameMapBuilder frameMapBuilder; + + private void setValueBlocked(Value location, int direction) { + assert direction == 1 || direction == -1 : "out of bounds"; + if (isStackSlotValue(location)) { + int stackIdx = getStackArrayIndex(asStackSlotValue(location)); + if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { + // incoming stack arguments can be ignored + return; + } + if (stackIdx >= stackBlocked.length) { + stackBlocked = Arrays.copyOf(stackBlocked, stackIdx + 1); + } + stackBlocked[stackIdx] += direction; + } else { + assert direction == 1 || direction == -1 : "out of bounds"; + if (isRegister(location)) { + registerBlocked[asRegister(location).number] += direction; + } else { + throw JVMCIError.shouldNotReachHere("unhandled value " + location); + } + } + } + + private int valueBlocked(Value location) { + if (isStackSlotValue(location)) { + int stackIdx = getStackArrayIndex(asStackSlotValue(location)); + if (stackIdx == STACK_SLOT_IN_CALLER_FRAME_IDX) { + // incoming stack arguments are always blocked (aka they can not be written) + return 1; + } + if (stackIdx >= stackBlocked.length) { + return 0; + } + return stackBlocked[stackIdx]; + } + if (isRegister(location)) { + return registerBlocked[asRegister(location).number]; + } + throw JVMCIError.shouldNotReachHere("unhandled value " + location); + } + + private static boolean areMultipleReadsAllowed() { + return true; + } + + private boolean hasMappings() { + return mappingFrom.size() > 0; + } + + private SpillMoveFactory getSpillMoveFactory() { + return spillMoveFactory; + } + + private Register[] getRegisters() { + return frameMapBuilder.getRegisterConfig().getAllocatableRegisters(); + } + + public TraceGlobalMoveResolver(LIRGenerationResult res, SpillMoveFactory spillMoveFactory, Architecture arch) { + + this.mappingFrom = new ArrayList<>(8); + this.mappingTo = new ArrayList<>(8); + this.insertIdx = -1; + this.insertionBuffer = new LIRInsertionBuffer(); + + this.frameMapBuilder = res.getFrameMapBuilder(); + this.spillMoveFactory = spillMoveFactory; + this.registerBlocked = new int[arch.getRegisters().length]; + + FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder; + this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()]; + + FrameMap frameMap = frameMapBuilderTool.getFrameMap(); + this.firstVirtualStackIndex = !frameMap.frameNeedsAllocating() ? 0 : frameMap.currentFrameSize() + 1; + } + + private boolean checkEmpty() { + for (int i = 0; i < stackBlocked.length; i++) { + assert stackBlocked[i] == 0 : "stack map must be empty before and after processing"; + } + assert mappingFrom.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing"; + for (int i = 0; i < getRegisters().length; i++) { + assert registerBlocked[i] == 0 : "register map must be empty before and after processing"; + } + return true; + } + + private boolean verifyBeforeResolve() { + assert mappingFrom.size() == mappingTo.size() : "length must be equal"; + assert insertIdx != -1 : "insert position not set"; + + int i; + int j; + if (!areMultipleReadsAllowed()) { + for (i = 0; i < mappingFrom.size(); i++) { + for (j = i + 1; j < mappingFrom.size(); j++) { + assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice"; + } + } + } + + for (i = 0; i < mappingTo.size(); i++) { + for (j = i + 1; j < mappingTo.size(); j++) { + assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice"; + } + } + + for (i = 0; i < mappingTo.size(); i++) { + Value to = mappingTo.get(i); + assert !isStackSlotValue(to) || getStackArrayIndex(asStackSlotValue(to)) != STACK_SLOT_IN_CALLER_FRAME_IDX : "Cannot move to in argument: " + to; + } + + HashSet<Value> usedRegs = new HashSet<>(); + if (!areMultipleReadsAllowed()) { + for (i = 0; i < mappingFrom.size(); i++) { + Value from = mappingFrom.get(i); + if (from != null && !isIllegal(from)) { + boolean unique = usedRegs.add(from); + assert unique : "cannot read from same register twice"; + } + } + } + + usedRegs.clear(); + for (i = 0; i < mappingTo.size(); i++) { + Value to = mappingTo.get(i); + if (isIllegal(to)) { + // After insertion the location may become illegal, so don't check it since multiple + // intervals might be illegal. + continue; + } + boolean unique = usedRegs.add(to); + assert unique : "cannot write to same register twice"; + } + + return true; + } + + // mark assignedReg and assignedRegHi of the interval as blocked + private void block(Value location) { + if (mightBeBlocked(location)) { + assert areMultipleReadsAllowed() || valueBlocked(location) == 0 : "location already marked as used: " + location; + setValueBlocked(location, 1); + Debug.log("block %s", location); + } + } + + // mark assignedReg and assignedRegHi of the interval as unblocked + private void unblock(Value location) { + if (mightBeBlocked(location)) { + assert valueBlocked(location) > 0 : "location already marked as unused: " + location; + setValueBlocked(location, -1); + Debug.log("unblock %s", location); + } + } + + /** + * Checks if the {@linkplain Interval#location() location} of {@code to} is not blocked or is + * only blocked by {@code from}. + */ + private boolean safeToProcessMove(Value fromLocation, Value toLocation) { + if (mightBeBlocked(toLocation)) { + if ((valueBlocked(toLocation) > 1 || (valueBlocked(toLocation) == 1 && !isMoveToSelf(fromLocation, toLocation)))) { + return false; + } + } + + return true; + } + + public static boolean isMoveToSelf(Value from, Value to) { + assert to != null; + if (to.equals(from)) { + return true; + } + if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) { + assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from); + return true; + } + return false; + } + + private static boolean mightBeBlocked(Value location) { + return isRegister(location) || isStackSlotValue(location); + } + + private void createInsertionBuffer(List<LIRInstruction> list) { + assert !insertionBuffer.initialized() : "overwriting existing buffer"; + insertionBuffer.init(list); + } + + private void appendInsertionBuffer() { + if (insertionBuffer.initialized()) { + insertionBuffer.finish(); + } + assert !insertionBuffer.initialized() : "must be uninitialized now"; + + insertIdx = -1; + } + + private void insertMove(Value fromOperand, AllocatableValue toOperand) { + assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand; + assert LIRKind.verifyMoveKinds(fromOperand.getLIRKind(), fromOperand.getLIRKind()) : "move between different types"; + assert insertIdx != -1 : "must setup insert position first"; + + insertionBuffer.append(insertIdx, createMove(fromOperand, toOperand)); + + if (Debug.isLogEnabled()) { + Debug.log("insert move from %s to %s at %d", fromOperand, toOperand, insertIdx); + } + } + + /** + * @param fromOpr {@link Interval#operand operand} of the {@code from} interval + * @param toOpr {@link Interval#operand operand} of the {@code to} interval + */ + private LIRInstruction createMove(Value fromOpr, AllocatableValue toOpr) { + if (isStackSlotValue(toOpr) && isStackSlotValue(fromOpr)) { + return getSpillMoveFactory().createStackMove(toOpr, fromOpr); + } + return getSpillMoveFactory().createMove(toOpr, fromOpr); + } + + private void resolveMappings() { + try (Indent indent = Debug.logAndIndent("resolveMapping")) { + assert verifyBeforeResolve(); + if (Debug.isLogEnabled()) { + printMapping(); + } + + // Block all registers that are used as input operands of a move. + // When a register is blocked, no move to this register is emitted. + // This is necessary for detecting cycles in moves. + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + Value from = mappingFrom.get(i); + block(from); + } + + int spillCandidate = -1; + while (mappingFrom.size() > 0) { + boolean processedInterval = false; + + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + Value fromInterval = mappingFrom.get(i); + AllocatableValue toInterval = mappingTo.get(i); + + Value fromLocation = fromInterval; + AllocatableValue toLocation = toInterval; + if (safeToProcessMove(fromLocation, toLocation)) { + // this interval can be processed because target is free + insertMove(fromLocation, toLocation); + unblock(fromLocation); + mappingFrom.remove(i); + mappingTo.remove(i); + + processedInterval = true; + } else if (fromInterval != null && isRegister(fromLocation)) { + // this interval cannot be processed now because target is not free + // it starts in a register, so it is a possible candidate for spilling + spillCandidate = i; + } + } + + if (!processedInterval) { + breakCycle(spillCandidate); + } + } + } + + // check that all intervals have been processed + assert checkEmpty(); + } + + private void breakCycle(int spillCandidate) { + // no move could be processed because there is a cycle in the move list + // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory + assert spillCandidate != -1 : "no interval in register for spilling found"; + + // create a new spill interval and assign a stack slot to it + Value from = mappingFrom.get(spillCandidate); + try (Indent indent = Debug.logAndIndent("BreakCycle: %s", from)) { + StackSlotValue spillSlot = frameMapBuilder.allocateSpillSlot(from.getLIRKind()); + if (Debug.isLogEnabled()) { + Debug.log("created new slot for spilling: %s", spillSlot); + } + // insert a move from register to stack and update the mapping + insertMove(from, spillSlot); + block(spillSlot); + mappingFrom.set(spillCandidate, spillSlot); + unblock(from); + } + } + + private void printMapping() { + try (Indent indent = Debug.logAndIndent("Mapping")) { + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + Debug.log("move %s <- %s", mappingTo.get(i), mappingFrom.get(i)); + } + } + } + + public void setInsertPosition(List<LIRInstruction> insertList, int insertIdx) { + assert this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set"; + + createInsertionBuffer(insertList); + this.insertIdx = insertIdx; + } + + public void addMapping(Value from, AllocatableValue to) { + if (Debug.isLogEnabled()) { + Debug.log("add move mapping from %s to %s", from, to); + } + + assert !from.equals(to) : "from and to interval equal: " + from; + assert LIRKind.verifyMoveKinds(to.getLIRKind(), from.getLIRKind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getLIRKind(), to.getLIRKind(), from, to); + mappingFrom.add(from); + mappingTo.add(to); + } + + public void resolveAndAppendMoves() { + if (hasMappings()) { + resolveMappings(); + } + appendInsertionBuffer(); + } + + private int getStackArrayIndex(StackSlotValue stackSlotValue) { + if (isStackSlot(stackSlotValue)) { + return getStackArrayIndex(asStackSlot(stackSlotValue)); + } + if (isVirtualStackSlot(stackSlotValue)) { + return getStackArrayIndex(asVirtualStackSlot(stackSlotValue)); + } + throw JVMCIError.shouldNotReachHere("Unhandled StackSlotValue: " + stackSlotValue); + } + + private int getStackArrayIndex(StackSlot stackSlot) { + int stackIdx; + if (stackSlot.isInCallerFrame()) { + // incoming stack arguments can be ignored + stackIdx = STACK_SLOT_IN_CALLER_FRAME_IDX; + } else { + assert stackSlot.getRawAddFrameSize() : "Unexpected stack slot: " + stackSlot; + int offset = -stackSlot.getRawOffset(); + assert 0 <= offset && offset < firstVirtualStackIndex : String.format("Wrong stack slot offset: %d (first virtual stack slot index: %d", offset, firstVirtualStackIndex); + stackIdx = offset; + } + return stackIdx; + } + + private int getStackArrayIndex(VirtualStackSlot virtualStackSlot) { + return firstVirtualStackIndex + virtualStackSlot.getId(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScan.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,138 @@ +/* + * 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.lir.alloc.trace; + +import static com.oracle.graal.lir.alloc.trace.TraceLinearScan.Options.*; +import static com.oracle.graal.compiler.common.GraalOptions.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.options.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.ssa.*; +import com.oracle.graal.lir.alloc.lsra.ssi.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext; + +public final class TraceLinearScan extends LinearScan { + + public static class Options { + // @formatter:off + @Option(help = "Use simplified lifetime analysis.", type = OptionType.Debug) + public static final OptionValue<Boolean> TraceRAsimpleLifetimeAnalysis = new OptionValue<>(true); + // @formatter:on + } + + private final TraceBuilderResult<?> traceBuilderResult; + + public TraceLinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory, RegisterAllocationConfig regAllocConfig, + List<? extends AbstractBlockBase<?>> sortedBlocks, TraceBuilderResult<?> traceBuilderResult) { + super(target, res, spillMoveFactory, regAllocConfig, sortedBlocks); + this.traceBuilderResult = traceBuilderResult; + } + + @Override + protected <B extends AbstractBlockBase<B>> void allocate(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, + SpillMoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig) { + + /* + * This is the point to enable debug logging for the whole register allocation. + */ + try (Indent indent = Debug.logAndIndent("LinearScan allocate")) { + AllocationContext context = new AllocationContext(spillMoveFactory, registerAllocationConfig); + + createLifetimeAnalysisPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + + try (Scope s = Debug.scope("AfterLifetimeAnalysis", (Object) intervals())) { + sortIntervalsBeforeAllocation(); + + createRegisterAllocationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + + if (LinearScan.Options.LIROptLSRAOptimizeSpillPosition.getValue()) { + createOptimizeSpillPositionPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + } + // resolve intra-trace data-flow + LinearScanResolveDataFlowPhase dataFlowPhase = createResolveDataFlowPhase(); + dataFlowPhase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), "%s", dataFlowPhase.getName()); + + LinearScanAssignLocationsPhase assignPhase = createAssignLocationsPhase(); + assignPhase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, false); + + if (DetailedAsserts.getValue()) { + verifyIntervals(); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + } + } + + @Override + protected MoveResolver createMoveResolver() { + SSAMoveResolver moveResolver = new SSAMoveResolver(this); + assert moveResolver.checkEmpty(); + return moveResolver; + } + + @Override + protected LinearScanLifetimeAnalysisPhase createLifetimeAnalysisPhase() { + if (TraceRAsimpleLifetimeAnalysis.getValue()) { + return new TraceSimpleLifetimeAnalysisPhase(this, traceBuilderResult); + } + return new TraceLinearScanLifetimeAnalysisPhase(this, traceBuilderResult); + } + + @Override + protected LinearScanResolveDataFlowPhase createResolveDataFlowPhase() { + return new TraceLinearScanResolveDataFlowPhase(this); + } + + @Override + protected LinearScanEliminateSpillMovePhase createSpillMoveEliminationPhase() { + return new SSILinearScanEliminateSpillMovePhase(this); + } + + @Override + public void printIntervals(String label) { + if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) { + super.printIntervals(label); + } + } + + @Override + public void printLir(String label, boolean hirValid) { + if (Debug.isDumpEnabled(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL)) { + Debug.dump(TraceRegisterAllocationPhase.TRACE_DUMP_LEVEL, sortedBlocks(), label); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,290 @@ +/* + * 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.lir.alloc.trace; + +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.lir.LIRValueUtil.*; +import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; +import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; +import com.oracle.graal.lir.alloc.lsra.LinearScan.BlockData; +import com.oracle.graal.lir.ssi.*; + +public class TraceLinearScanLifetimeAnalysisPhase extends LinearScanLifetimeAnalysisPhase { + + private final TraceBuilderResult<?> traceBuilderResult; + + public TraceLinearScanLifetimeAnalysisPhase(LinearScan linearScan, TraceBuilderResult<?> traceBuilderResult) { + super(linearScan); + this.traceBuilderResult = traceBuilderResult; + } + + private boolean sameTrace(AbstractBlockBase<?> a, AbstractBlockBase<?> b) { + return traceBuilderResult.getTraceForBlock(b) == traceBuilderResult.getTraceForBlock(a); + } + + private boolean isAllocatedOrCurrent(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) { + return traceBuilderResult.getTraceForBlock(other) <= traceBuilderResult.getTraceForBlock(currentBlock); + } + + static void setHint(final LIRInstruction op, Interval target, Interval source) { + Interval currentHint = target.locationHint(false); + if (currentHint == null || currentHint.from() > target.from()) { + /* + * Update hint if there was none or if the hint interval starts after the hinted + * interval. + */ + target.setLocationHint(source); + if (Debug.isLogEnabled()) { + Debug.log("operation at opId %d: added hint from interval %d (%s) to %d (%s)", op.id(), source.operandNumber, source, target.operandNumber, target); + } + } + } + + @Override + protected void changeSpillDefinitionPos(LIRInstruction op, AllocatableValue operand, Interval interval, int defPos) { + assert interval.isSplitParent() : "can only be called for split parents"; + + switch (interval.spillState()) { + case NoDefinitionFound: + // assert interval.spillDefinitionPos() == -1 : "must no be set before"; + interval.setSpillDefinitionPos(defPos); + if (!(op instanceof LabelOp)) { + // Do not update state for labels. This will be done afterwards. + interval.setSpillState(SpillState.NoSpillStore); + } + break; + + case NoSpillStore: + assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; + if (defPos < interval.spillDefinitionPos() - 2) { + // second definition found, so no spill optimization possible for this interval + interval.setSpillState(SpillState.NoOptimization); + } else { + // two consecutive definitions (because of two-operand LIR form) + assert allocator.blockForId(defPos) == allocator.blockForId(interval.spillDefinitionPos()) : "block must be equal"; + } + break; + + case NoOptimization: + // nothing to do + break; + + default: + throw new BailoutException("other states not allowed at this time"); + } + } + + @Override + protected void buildIntervals() { + super.buildIntervals(); + postBuildIntervals(); + } + + protected void postBuildIntervals() { + // fix spill state for phi/sigma intervals + for (Interval interval : allocator.intervals()) { + if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) { + // there was a definition in a phi/sigma + interval.setSpillState(SpillState.NoSpillStore); + } + } + if (TraceRAuseInterTraceHints.getValue()) { + addInterTraceHints(); + } + } + + private void addInterTraceHints() { + // set hints for phi/sigma intervals + LIR lir = allocator.getLIR(); + for (AbstractBlockBase<?> block : allocator.sortedBlocks()) { + LabelOp label = SSIUtil.incoming(lir, block); + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + if (isAllocatedOrCurrent(block, pred)) { + BlockEndOp outgoing = SSIUtil.outgoing(lir, pred); + for (int i = 0; i < outgoing.getOutgoingSize(); i++) { + Value toValue = label.getIncomingValue(i); + if (!isIllegal(toValue)) { + Value fromValue = outgoing.getOutgoingValue(i); + assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue; + + if (!isStackSlotValue(fromValue) && !isConstant(fromValue)) { + Interval from = allocator.getOrCreateInterval((AllocatableValue) fromValue); + Interval to = allocator.getOrCreateInterval((AllocatableValue) toValue); + setHint(label, to, from); + } + } + } + } + } + } + /* + * Set the first range for fixed intervals to [-1, 0] to avoid intersection with incoming + * values. + */ + for (Interval interval : allocator.intervals()) { + if (interval != null && isRegister(interval.operand)) { + Range range = interval.first(); + if (range == Range.EndMarker) { + interval.addRange(-1, 0); + } else if (range.from == 0 && range.to == 1) { + range.from = -1; + range.to = 0; + } + } + } + } + + @Override + protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { + if (op instanceof LabelOp) { + // skip method header + return RegisterPriority.None; + } + return super.registerPriorityOfOutputOperand(op); + } + + @Override + protected void handleMethodArguments(LIRInstruction op) { + if (op instanceof MoveOp) { + // do not optimize method arguments + return; + } + super.handleMethodArguments(op); + } + + /** + * Performs a backward dataflow analysis to compute global live sets (i.e. + * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. + */ + @Override + protected void computeGlobalLiveSets() { + try (Indent indent = Debug.logAndIndent("compute global live sets")) { + int numBlocks = allocator.blockCount(); + boolean changeOccurred; + boolean changeOccurredInBlock; + int iterationCount = 0; + BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations + + /* + * Perform a backward dataflow analysis to compute liveOut and liveIn for each block. + * The loop is executed until a fixpoint is reached (no changes in an iteration). + */ + do { + changeOccurred = false; + + try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { + + // iterate all blocks in reverse order + for (int i = numBlocks - 1; i >= 0; i--) { + AbstractBlockBase<?> block = allocator.blockAt(i); + BlockData blockSets = allocator.getBlockData(block); + + changeOccurredInBlock = false; + + /* liveOut(block) is the union of liveIn(sux), for successors sux of block. */ + int n = block.getSuccessorCount(); + if (n > 0) { + liveOut.clear(); + // block has successors + if (n > 0) { + for (AbstractBlockBase<?> successor : block.getSuccessors()) { + if (allocator.sortedBlocks().contains(successor)) { + liveOut.or(allocator.getBlockData(successor).liveIn); + } + } + } + + if (!blockSets.liveOut.equals(liveOut)) { + /* + * A change occurred. Swap the old and new live out sets to avoid + * copying. + */ + BitSet temp = blockSets.liveOut; + blockSets.liveOut = liveOut; + liveOut = temp; + + changeOccurred = true; + changeOccurredInBlock = true; + } + } + + if (iterationCount == 0 || changeOccurredInBlock) { + /* + * liveIn(block) is the union of liveGen(block) with (liveOut(block) & + * !liveKill(block)). + * + * Note: liveIn has to be computed only in first iteration or if liveOut + * has changed! + */ + BitSet liveIn = blockSets.liveIn; + liveIn.clear(); + liveIn.or(blockSets.liveOut); + liveIn.andNot(blockSets.liveKill); + liveIn.or(blockSets.liveGen); + + if (Debug.isLogEnabled()) { + Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); + } + } + } + iterationCount++; + + if (changeOccurred && iterationCount > 50) { + throw new BailoutException("too many iterations in computeGlobalLiveSets"); + } + } + } while (changeOccurred); + + if (DetailedAsserts.getValue()) { + verifyLiveness(); + } + + // check that the liveIn set of the first block is empty + AbstractBlockBase<?> startBlock = allocator.blockAt(0); + if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) { + if (DetailedAsserts.getValue()) { + reportFailure(numBlocks); + } + // bailout if this occurs in product mode. + throw new JVMCIError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanResolveDataFlowPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,108 @@ +/* + * 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.lir.alloc.trace; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.ssa.SSAUtil.PhiValueVisitor; +import com.oracle.graal.lir.ssi.*; + +public class TraceLinearScanResolveDataFlowPhase extends LinearScanResolveDataFlowPhase { + + private static final DebugMetric numSSIResolutionMoves = Debug.metric("SSI LSRA[numSSIResolutionMoves]"); + private static final DebugMetric numStackToStackMoves = Debug.metric("SSI LSRA[numStackToStackMoves]"); + + public TraceLinearScanResolveDataFlowPhase(LinearScan allocator) { + super(allocator); + } + + @Override + protected void optimizeEmptyBlocks(MoveResolver moveResolver, BitSet blockCompleted) { + // do not optimize + } + + @Override + protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) { + assert midBlock == null; + if (containedInTrace(fromBlock) && containedInTrace(toBlock)) { + super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver); + SSIUtil.forEachValuePair(allocator.getLIR(), toBlock, fromBlock, new MyPhiValueVisitor(moveResolver, toBlock, fromBlock)); + } + + } + + private boolean containedInTrace(AbstractBlockBase<?> block) { + return allocator.sortedBlocks().contains(block); + } + + private class MyPhiValueVisitor implements PhiValueVisitor { + final MoveResolver moveResolver; + final int toId; + final int fromId; + + public MyPhiValueVisitor(MoveResolver moveResolver, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock) { + this.moveResolver = moveResolver; + toId = allocator.getFirstLirInstructionId(toBlock); + fromId = allocator.getLastLirInstructionId(fromBlock); + assert fromId >= 0; + } + + public void visit(Value phiIn, Value phiOut) { + assert !isRegister(phiOut) : "Out is a register: " + phiOut; + assert !isRegister(phiIn) : "In is a register: " + phiIn; + if (Value.ILLEGAL.equals(phiIn)) { + // The value not needed in this branch. + return; + } + if (isVirtualStackSlot(phiIn) && isVirtualStackSlot(phiOut) && phiIn.equals(phiOut)) { + // no need to handle virtual stack slots + return; + } + Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toId, LIRInstruction.OperandMode.DEF); + if (isConstant(phiOut)) { + numSSIResolutionMoves.increment(); + moveResolver.addMapping(phiOut, toInterval); + } else { + Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), fromId, LIRInstruction.OperandMode.DEF); + if (fromInterval != toInterval) { + numSSIResolutionMoves.increment(); + if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) { + moveResolver.addMapping(fromInterval, toInterval); + } else { + numStackToStackMoves.increment(); + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceRegisterAllocationPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,142 @@ +/* + * 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.lir.alloc.trace; + +import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.options.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.lir.ssi.*; + +public class TraceRegisterAllocationPhase extends AllocationPhase { + public static class Options { + // @formatter:off + @Option(help = "Use inter-trace register hints.", type = OptionType.Debug) + public static final OptionValue<Boolean> TraceRAuseInterTraceHints = new OptionValue<>(true); + @Option(help = "Use special allocator for trivial blocks.", type = OptionType.Debug) + public static final OptionValue<Boolean> TraceRAtrivialBlockAllocator = new OptionValue<>(true); + // @formatter:on + } + + static final int TRACE_DUMP_LEVEL = 3; + private static final DebugMetric trivialTracesMetric = Debug.metric("TraceRA[trivialTraces]"); + private static final DebugMetric tracesMetric = Debug.metric("TraceRA[traces]"); + + @Override + protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + LIR lir = lirGenRes.getLIR(); + assert SSIVerifier.verify(lir) : "LIR not in SSI form."; + B startBlock = linearScanOrder.get(0); + assert startBlock.equals(lir.getControlFlowGraph().getStartBlock()); + TraceBuilderResult<B> resultTraces = TraceBuilder.computeTraces(startBlock, linearScanOrder); + + Debug.dump(lir, "Before TraceRegisterAllocation"); + int traceNumber = 0; + for (List<B> trace : resultTraces.getTraces()) { + try (Indent i = Debug.logAndIndent("Allocating Trace%d: %s", traceNumber, trace); Scope s = Debug.scope("AllocateTrace", trace)) { + tracesMetric.increment(); + if (trivialTracesMetric.isEnabled() && isTrivialTrace(lir, trace)) { + trivialTracesMetric.increment(); + } + Debug.dump(TRACE_DUMP_LEVEL, trace, "Trace" + traceNumber + ": " + trace); + if (TraceRAtrivialBlockAllocator.getValue() && isTrivialTrace(lir, trace)) { + new TraceTrivialAllocator(resultTraces).apply(target, lirGenRes, codeEmittingOrder, trace, new AllocationContext(spillMoveFactory, registerAllocationConfig), false); + } else { + TraceLinearScan allocator = new TraceLinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, trace, resultTraces); + allocator.allocate(target, lirGenRes, codeEmittingOrder, linearScanOrder, spillMoveFactory, registerAllocationConfig); + } + Debug.dump(TRACE_DUMP_LEVEL, trace, "After Trace" + traceNumber + ": " + trace); + traceNumber++; + } catch (Throwable e) { + throw Debug.handle(e); + } + unnumberInstructions(trace, lir); + } + Debug.dump(lir, "After trace allocation"); + + new TraceGlobalMoveResolutionPhase(resultTraces).apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, new AllocationContext(spillMoveFactory, registerAllocationConfig)); + + if (replaceStackToStackMoves(lir, spillMoveFactory)) { + Debug.dump(lir, "After fixing stack to stack moves"); + } + /* + * Incoming Values are needed for the RegisterVerifier, otherwise SIGMAs/PHIs where the Out + * and In value matches (ie. there is no resolution move) are falsely detected as errors. + */ + for (AbstractBlockBase<?> toBlock : lir.getControlFlowGraph().getBlocks()) { + if (toBlock.getPredecessorCount() != 0) { + SSIUtil.removeIncoming(lir, toBlock); + } else { + assert lir.getControlFlowGraph().getStartBlock().equals(toBlock); + } + SSIUtil.removeOutgoing(lir, toBlock); + } + } + + static boolean isTrivialTrace(LIR lir, List<? extends AbstractBlockBase<?>> trace) { + return trace.size() == 1 && lir.getLIRforBlock(trace.iterator().next()).size() == 2; + } + + /** + * Fixup stack to stack moves introduced by stack arguments. + * + * TODO (je) find a better solution. + */ + private static boolean replaceStackToStackMoves(LIR lir, SpillMoveFactory spillMoveFactory) { + boolean changed = false; + for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) { + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + for (int i = 0; i < instructions.size(); i++) { + LIRInstruction inst = instructions.get(i); + + if (inst instanceof MoveOp) { + MoveOp move = (MoveOp) inst; + if (isStackSlotValue(move.getInput()) && isStackSlotValue(move.getResult())) { + instructions.set(i, spillMoveFactory.createStackMove(move.getResult(), move.getInput())); + changed = true; + } + } + } + } + return changed; + } + + private static void unnumberInstructions(List<? extends AbstractBlockBase<?>> trace, LIR lir) { + trace.stream().flatMap(b -> lir.getLIRforBlock(b).stream()).forEach(op -> op.setId(-1)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceSimpleLifetimeAnalysisPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,282 @@ +/* + * 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.lir.alloc.trace; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.lsra.Interval.RegisterPriority; +import com.oracle.graal.lir.alloc.lsra.Interval.SpillState; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; + +public class TraceSimpleLifetimeAnalysisPhase extends TraceLinearScanLifetimeAnalysisPhase { + + public TraceSimpleLifetimeAnalysisPhase(LinearScan allocator, TraceBuilderResult<?> traceBuilderResult) { + super(allocator, traceBuilderResult); + } + + @Override + protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + numberInstructions(); + allocator.printLir("Before register allocation", true); + buildIntervals(); + } + + @Override + protected void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + if (isRegister(operand)) { + super.addUse(operand, from, to, registerPriority, kind); + return; + } + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + Range r = interval.first(); + if (r == Range.EndMarker) { + interval.addRange(from, to); + } else if (r.from > from) { + r.from = from; + } + + // Register use position at even instruction id. + interval.addUsePos(to & ~1, registerPriority); + + if (Debug.isLogEnabled()) { + Debug.log("add use: %s, at %d (%s)", interval, to, registerPriority.name()); + } + } + + @Override + protected void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + if (isRegister(operand)) { + super.addTemp(operand, tempPos, registerPriority, kind); + return; + } + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + Range r = interval.first(); + if (r == Range.EndMarker) { + interval.addRange(tempPos, tempPos + 1); + } else if (r.from > tempPos) { + r.from = tempPos; + } + interval.addUsePos(tempPos, registerPriority); + interval.addMaterializationValue(null); + + if (Debug.isLogEnabled()) { + Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name()); + } + } + + @Override + protected void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, LIRKind kind) { + if (!allocator.isProcessed(operand)) { + return; + } + if (isRegister(operand)) { + super.addDef(operand, op, registerPriority, kind); + return; + } + int defPos = op.id(); + + Interval interval = allocator.getOrCreateInterval(operand); + if (!kind.equals(LIRKind.Illegal)) { + interval.setKind(kind); + } + + Range r = interval.first(); + if (r == Range.EndMarker) { + /* + * Dead value - make vacuous interval also add register priority for dead intervals + */ + interval.addRange(defPos, defPos + 1); + interval.addUsePos(defPos, registerPriority); + if (Debug.isLogEnabled()) { + Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos); + } + } else { + /* + * Update the starting point (when a range is first created for a use, its start is the + * beginning of the current block until a def is encountered). + */ + r.from = defPos; + interval.addUsePos(defPos, registerPriority); + + } + + changeSpillDefinitionPos(op, operand, interval, defPos); + if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal() && isStackSlot(operand)) { + // detection of method-parameters and roundfp-results + interval.setSpillState(SpillState.StartInMemory); + } + interval.addMaterializationValue(getMaterializedValue(op, operand, interval)); + + if (Debug.isLogEnabled()) { + Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name()); + } + } + + @Override + protected void buildIntervals() { + + try (Indent indent = Debug.logAndIndent("build intervals")) { + InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, true); + } + }; + + InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + int opId = op.id(); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + int opId = op.id(); + RegisterPriority p = registerPriorityOfInputOperand(flags); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getLIRKind()); + addRegisterHint(op, operand, mode, flags, false); + } + }; + + InstructionValueConsumer stateProc = (op, operand, mode, flags) -> { + if (LinearScan.isVariableOrRegister(operand)) { + int opId = op.id(); + int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId))); + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getLIRKind()); + } + }; + + // create a list with all caller-save registers (cpu, fpu, xmm) + Register[] callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters(); + + // iterate all blocks in reverse order + for (int i = allocator.blockCount() - 1; i >= 0; i--) { + + AbstractBlockBase<?> block = allocator.blockAt(i); + // TODO (je) make empty bitset - remove + allocator.getBlockData(block).liveIn = new BitSet(); + allocator.getBlockData(block).liveOut = new BitSet(); + try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { + + List<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block); + + /* + * Iterate all instructions of the block in reverse order. definitions of + * intervals are processed before uses. + */ + for (int j = instructions.size() - 1; j >= 0; j--) { + final LIRInstruction op = instructions.get(j); + final int opId = op.id(); + + try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { + + // add a temp range for each register if operation destroys + // caller-save registers + if (op.destroysCallerSavedRegisters()) { + for (Register r : callerSaveRegs) { + if (allocator.attributes(r).isAllocatable()) { + addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal); + } + } + if (Debug.isLogEnabled()) { + Debug.log("operation destroys all caller-save registers"); + } + } + + op.visitEachOutput(outputConsumer); + op.visitEachTemp(tempConsumer); + op.visitEachAlive(aliveConsumer); + op.visitEachInput(inputConsumer); + + /* + * Add uses of live locals from interpreter's point of view for proper + * debug information generation. Treat these operands as temp values (if + * the live range is extended to a call site, the value would be in a + * register at the call otherwise). + */ + op.visitEachState(stateProc); + + // special steps for some instructions (especially moves) + handleMethodArguments(op); + + } + + } // end of instruction iteration + } + allocator.printIntervals("After Block " + block); + } // end of block iteration + + /* + * Add the range [0, 1] to all fixed intervals. the register allocator need not handle + * unhandled fixed intervals. + */ + for (Interval interval : allocator.intervals()) { + if (interval != null && isRegister(interval.operand)) { + interval.addRange(0, 1); + } + } + } + postBuildIntervals(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceTrivialAllocator.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,90 @@ +/* + * 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.lir.alloc.trace; + +import static com.oracle.graal.lir.LIRValueUtil.*; +import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.lir.ssi.*; +import com.oracle.graal.lir.util.*; + +/** + * Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other + * than the {@link LabelOp} and the {@link BlockEndOp}. + */ +public class TraceTrivialAllocator extends AllocationPhase { + + private final TraceBuilderResult<?> resultTraces; + + public TraceTrivialAllocator(TraceBuilderResult<?> resultTraces) { + this.resultTraces = resultTraces; + } + + @Override + protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> trace, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + LIR lir = lirGenRes.getLIR(); + assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace; + B block = trace.iterator().next(); + + AbstractBlockBase<?> pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block); + + VariableVirtualStackValueMap<Variable, Value> variableMap = new VariableVirtualStackValueMap<>(lir.nextVariable(), 0); + SSIUtil.forEachValuePair(lir, block, pred, (to, from) -> { + if (isVariable(to)) { + variableMap.put(asVariable(to), from); + } + }); + + ValueProcedure outputConsumer = (value, mode, flags) -> { + if (isVariable(value)) { + return variableMap.get(asVariable(value)); + } + return value; + }; + + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + for (LIRInstruction op : instructions) { + + op.forEachOutput(outputConsumer); + op.forEachTemp(outputConsumer); + op.forEachAlive(outputConsumer); + op.forEachInput(outputConsumer); + op.forEachState(outputConsumer); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,42 @@ +/* + * 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.lir.alloc.trace; + +import com.oracle.graal.compiler.common.alloc.TraceBuilder.TraceBuilderResult; +import com.oracle.graal.compiler.common.cfg.*; + +class TraceUtil { + + static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult<?> traceResult, AbstractBlockBase<?> block) { + AbstractBlockBase<?> bestPred = null; + int bestTraceId = traceResult.getTraceForBlock(block); + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + int predTraceId = traceResult.getTraceForBlock(pred); + if (predTraceId < bestTraceId) { + bestPred = pred; + bestTraceId = predTraceId; + } + } + return bestPred; + } +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * 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.lir.dfa; - -import jdk.internal.jvmci.meta.*; - -abstract class LiveValueSet<S extends LiveValueSet<S>> { - - public abstract void put(Value v); - - public abstract void remove(Value v); - - public abstract void putAll(S s); - - public abstract S copy(); -}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java Wed Jul 29 11:59:18 2015 +0200 @@ -27,7 +27,9 @@ import java.util.*; import jdk.internal.jvmci.code.*; + import com.oracle.graal.debug.*; + import jdk.internal.jvmci.meta.*; import com.oracle.graal.compiler.common.cfg.*; @@ -35,8 +37,9 @@ import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.util.*; -public abstract class LocationMarker<T extends AbstractBlockBase<T>, S extends LiveValueSet<S>> { +public abstract class LocationMarker<T extends AbstractBlockBase<T>, S extends ValueSet<S>> { private final LIR lir; private final BlockMap<S> liveInMap;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -49,105 +49,7 @@ new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build(); } - private static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, Marker<T>.RegStackValueSet> { - - private final class RegStackValueSet extends LiveValueSet<Marker<T>.RegStackValueSet> { - - private final ValueSet registers; - private final ValueSet stack; - private Set<Value> extraStack; - - public RegStackValueSet() { - registers = new ValueSet(); - stack = new ValueSet(); - } - - private RegStackValueSet(RegStackValueSet s) { - registers = new ValueSet(s.registers); - stack = new ValueSet(s.stack); - if (s.extraStack != null) { - extraStack = new HashSet<>(s.extraStack); - } - } - - @Override - public Marker<T>.RegStackValueSet copy() { - return new RegStackValueSet(this); - } - - @Override - public void put(Value v) { - if (isRegister(v)) { - int index = asRegister(v).getReferenceMapIndex(); - registers.put(index, v); - } else if (isStackSlot(v)) { - int index = frameMap.offsetForStackSlot(asStackSlot(v)); - assert index >= 0; - if (index % 4 == 0) { - stack.put(index / 4, v); - } else { - if (extraStack == null) { - extraStack = new HashSet<>(); - } - extraStack.add(v); - } - } - } - - @Override - public void putAll(RegStackValueSet v) { - registers.putAll(v.registers); - stack.putAll(v.stack); - if (v.extraStack != null) { - if (extraStack == null) { - extraStack = new HashSet<>(); - } - extraStack.addAll(v.extraStack); - } - } - - @Override - public void remove(Value v) { - if (isRegister(v)) { - int index = asRegister(v).getReferenceMapIndex(); - registers.put(index, null); - } else if (isStackSlot(v)) { - int index = frameMap.offsetForStackSlot(asStackSlot(v)); - assert index >= 0; - if (index % 4 == 0) { - stack.put(index / 4, null); - } else if (extraStack != null) { - extraStack.remove(v); - } - } - } - - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object obj) { - if (obj instanceof Marker.RegStackValueSet) { - RegStackValueSet other = (RegStackValueSet) obj; - return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack); - } else { - return false; - } - } - - @Override - public int hashCode() { - throw new UnsupportedOperationException(); - } - - public void addLiveValues(ReferenceMapBuilder refMap) { - registers.addLiveValues(refMap); - stack.addLiveValues(refMap); - if (extraStack != null) { - for (Value v : extraStack) { - refMap.addLiveValue(v); - } - } - } - } + static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, RegStackValueSet> { private final RegisterAttributes[] registerAttributes; @@ -157,8 +59,8 @@ } @Override - protected Marker<T>.RegStackValueSet newLiveValueSet() { - return new RegStackValueSet(); + protected RegStackValueSet newLiveValueSet() { + return new RegStackValueSet(frameMap); } @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.lir.gen.*; import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; import com.oracle.graal.lir.phases.*; +import com.oracle.graal.lir.util.*; /** * Record all derived reference base pointers in a frame state. @@ -48,16 +49,16 @@ private static final class Marker<T extends AbstractBlockBase<T>> extends LocationMarker<T, Marker<T>.BasePointersSet> { - private final class BasePointersSet extends LiveValueSet<Marker<T>.BasePointersSet> { + private final class BasePointersSet extends ValueSet<Marker<T>.BasePointersSet> { - private final ValueSet variables; + private final IndexedValueMap variables; public BasePointersSet() { - variables = new ValueSet(); + variables = new IndexedValueMap(); } private BasePointersSet(BasePointersSet s) { - variables = new ValueSet(s.variables); + variables = new IndexedValueMap(s.variables); } @Override @@ -68,6 +69,7 @@ @Override public void put(Value v) { Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase(); + assert !base.getLIRKind().isValue(); variables.put(base.index, base); } @@ -79,6 +81,7 @@ @Override public void remove(Value v) { Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase(); + assert !base.getLIRKind().isValue(); variables.put(base.index, null); } @@ -115,7 +118,7 @@ @Override protected void processState(LIRInstruction op, LIRFrameState info, BasePointersSet values) { - info.setLiveBasePointers(new ValueSet(values.variables)); + info.setLiveBasePointers(new IndexedValueMap(values.variables)); } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/RegStackValueSet.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,153 @@ +/* + * 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.lir.dfa; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.util.*; + +final class RegStackValueSet extends ValueSet<RegStackValueSet> { + + private final FrameMap frameMap; + private final IndexedValueMap registers; + private final IndexedValueMap stack; + private Set<Value> extraStack; + + public RegStackValueSet(FrameMap frameMap) { + this.frameMap = frameMap; + registers = new IndexedValueMap(); + stack = new IndexedValueMap(); + } + + private RegStackValueSet(FrameMap frameMap, RegStackValueSet s) { + this.frameMap = frameMap; + registers = new IndexedValueMap(s.registers); + stack = new IndexedValueMap(s.stack); + if (s.extraStack != null) { + extraStack = new HashSet<>(s.extraStack); + } + } + + @Override + public RegStackValueSet copy() { + return new RegStackValueSet(frameMap, this); + } + + @Override + public void put(Value v) { + if (!shouldProcessValue(v)) { + return; + } + if (isRegister(v)) { + int index = asRegister(v).getReferenceMapIndex(); + registers.put(index, v); + } else if (isStackSlot(v)) { + int index = frameMap.offsetForStackSlot(asStackSlot(v)); + assert index >= 0; + if (index % 4 == 0) { + stack.put(index / 4, v); + } else { + if (extraStack == null) { + extraStack = new HashSet<>(); + } + extraStack.add(v); + } + } + } + + @Override + public void putAll(RegStackValueSet v) { + registers.putAll(v.registers); + stack.putAll(v.stack); + if (v.extraStack != null) { + if (extraStack == null) { + extraStack = new HashSet<>(); + } + extraStack.addAll(v.extraStack); + } + } + + @Override + public void remove(Value v) { + if (!shouldProcessValue(v)) { + return; + } + if (isRegister(v)) { + int index = asRegister(v).getReferenceMapIndex(); + registers.put(index, null); + } else if (isStackSlot(v)) { + int index = frameMap.offsetForStackSlot(asStackSlot(v)); + assert index >= 0; + if (index % 4 == 0) { + stack.put(index / 4, null); + } else if (extraStack != null) { + extraStack.remove(v); + } + } + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegStackValueSet) { + RegStackValueSet other = (RegStackValueSet) obj; + return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack); + } else { + return false; + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + private static boolean shouldProcessValue(Value v) { + /* + * We always process registers because we have to track the largest register size that is + * alive across safepoints in order to save and restore them. + */ + return isRegister(v) || !v.getLIRKind().isValue(); + } + + public void addLiveValues(ReferenceMapBuilder refMap) { + ValueConsumer addLiveValue = new ValueConsumer() { + public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { + refMap.addLiveValue(value); + } + }; + registers.forEach(null, null, null, addLiveValue); + stack.forEach(null, null, null, addLiveValue); + if (extraStack != null) { + for (Value v : extraStack) { + refMap.addLiveValue(v); + } + } + } +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - * 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.lir.dfa; - -import java.util.*; - -import jdk.internal.jvmci.meta.*; - -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.OperandFlag; -import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.framemap.*; - -public final class ValueSet { - private Value[] values; - - ValueSet() { - values = Value.NO_VALUES; - } - - ValueSet(ValueSet other) { - int limit = other.values.length; - while (limit > 0) { - if (other.values[limit - 1] == null) { - limit--; - continue; - } - break; - } - values = new Value[limit]; - System.arraycopy(other.values, 0, values, 0, values.length); - } - - public Value get(int index) { - return values[index]; - } - - void put(int index, Value value) { - if (value != null && value.getLIRKind().isValue()) { - return; - } - if (values.length <= index) { - if (value == null) { - return; - } - Value[] newValues = new Value[index + 1]; - System.arraycopy(values, 0, newValues, 0, values.length); - values = newValues; - values[index] = value; - } else { - values[index] = value; - } - } - - public void putAll(ValueSet stack) { - Value[] otherValues = stack.values; - int limit = otherValues.length; - if (limit > values.length) { - while (limit > 0) { - if (otherValues[limit - 1] == null) { - limit--; - continue; - } - break; - } - if (limit > values.length) { - Value[] newValues = new Value[limit]; - System.arraycopy(values, 0, newValues, 0, values.length); - values = newValues; - } - } - for (int i = 0; i < limit; i++) { - Value value = otherValues[i]; - if (value != null) { - values[i] = value; - } - } - } - - @Override - public boolean equals(Object other) { - if (other instanceof ValueSet) { - ValueSet that = (ValueSet) other; - int limit = Math.min(values.length, that.values.length); - for (int i = 0; i < limit; i++) { - if (!Objects.equals(values[i], that.values[i])) { - return false; - } - } - for (int i = limit; i < values.length; i++) { - if (values[i] != null) { - return false; - } - } - for (int i = limit; i < that.values.length; i++) { - if (that.values[i] != null) { - return false; - } - } - return true; - } - return false; - } - - public void addLiveValues(ReferenceMapBuilder refMap) { - for (Value v : values) { - if (v != null) { - refMap.addLiveValue(v); - } - } - } - - public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueProcedure proc) { - for (int i = 0; i < values.length; i++) { - if (values[i] != null) { - values[i] = proc.doValue(inst, values[i], mode, flags); - } - } - } - - public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueConsumer consumer) { - for (Value v : values) { - if (v != null) { - consumer.visitValue(inst, v, mode, flags); - } - } - } - - @Override - public int hashCode() { - throw new UnsupportedOperationException(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("["); - boolean comma = false; - - for (int i = 0; i < values.length; i++) { - if (values[i] != null) { - if (comma) { - sb.append(", "); - } else { - comma = true; - } - - sb.append(i); - sb.append(": "); - sb.append(values[i]); - } - } - sb.append(']'); - return sb.toString(); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/BlockValueMap.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,35 @@ +/* + * 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.lir.gen; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; + +public interface BlockValueMap { + + void accessOperand(Value operand, AbstractBlockBase<?> block); + + void defineOperand(Value operand, AbstractBlockBase<?> block); + +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,8 +29,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.options.*; @@ -39,6 +37,7 @@ import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.common.spi.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.StandardOp.LabelOp;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,7 +22,10 @@ */ package com.oracle.graal.lir.phases; +import static com.oracle.graal.compiler.common.BackendOptions.UserOptions.*; + import com.oracle.graal.lir.alloc.lsra.*; +import com.oracle.graal.lir.alloc.trace.*; import com.oracle.graal.lir.dfa.*; import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext; import com.oracle.graal.lir.stackslotalloc.*; @@ -30,7 +33,11 @@ public class AllocationStage extends LIRPhaseSuite<AllocationContext> { public AllocationStage() { appendPhase(new MarkBasePointersPhase()); - appendPhase(new LinearScanPhase()); + if (TraceRA.getValue()) { + appendPhase(new TraceRegisterAllocationPhase()); + } else { + appendPhase(new LinearScanPhase()); + } // build frame map if (LSStackSlotAllocator.Options.LIROptLSStackSlotAllocator.getValue()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationStage.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PreAllocationOptimizationStage.java Wed Jul 29 11:59:18 2015 +0200 @@ -23,11 +23,13 @@ package com.oracle.graal.lir.phases; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.compiler.common.BackendOptions.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.constopt.*; import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; import com.oracle.graal.lir.ssa.*; +import com.oracle.graal.lir.ssi.*; public class PreAllocationOptimizationStage extends LIRPhaseSuite<PreAllocationOptimizationContext> { public PreAllocationOptimizationStage() { @@ -37,5 +39,8 @@ if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) { appendPhase(new ConstantLoadOptimization()); } + if (EnableSSIConstruction.getValue()) { + appendPhase(new SSIConstructionPhase()); + } } }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Wed Jul 29 11:59:18 2015 +0200 @@ -51,7 +51,8 @@ STACK2REG("Reg", "Stack"), CONST2REG("Reg", "Const"), REG2STACK("Stack", "Reg"), - CONST2STACK("Stack", "Const"); + CONST2STACK("Stack", "Const"), + STACK2STACK("Stack", "Stack"); private final String name; @@ -84,6 +85,9 @@ if (isConstant(src)) { return CONST2STACK; } + if (isStackSlot(src)) { + return STACK2STACK; + } } throw JVMCIError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src)); }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSADestructionPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -48,15 +48,15 @@ List<LIRInstruction> instructions = lir.getLIRforBlock(pred); - int insertBefore = SSAUtils.phiOutIndex(lir, pred); + int insertBefore = SSAUtil.phiOutIndex(lir, pred); PhiResolver resolver = PhiResolver.create(lirGen, new LIRInsertionBuffer(), instructions, insertBefore); - SSAUtils.forEachPhiValuePair(lir, block, pred, resolver::move); + SSAUtil.forEachPhiValuePair(lir, block, pred, resolver::move); resolver.dispose(); - SSAUtils.removePhiOut(lir, pred); + SSAUtil.removePhiOut(lir, pred); } - SSAUtils.removePhiIn(lir, block); + SSAUtil.removePhiIn(lir, block); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,176 @@ +/* + * 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.lir.ssa; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.JumpOp; +import com.oracle.graal.lir.StandardOp.LabelOp; + +/** + * Utilities for working with Static-Single-Assignment LIR form. + * + * <h2>Representation of <code>PHI</code>s</h2> + * + * There is no explicit <code>PHI</code> {@linkplain LIRInstruction}. Instead, they are implemented + * as parallel copy that span across a control-flow edge. + * + * The variables introduced by <code>PHI</code>s of a specific {@linkplain AbstractBlockBase merge + * block} are {@linkplain LabelOp#setIncomingValues attached} to the {@linkplain LabelOp} of the + * block. The outgoing values from the predecessor are {@link JumpOp#setOutgoingValues input} to the + * {@linkplain BlockEndOp} of the predecessor. Because there are no critical edges we know that the + * {@link BlockEndOp} of the predecessor has to be a {@link JumpOp}. + * + * <h3>Example:</h3> + * + * <pre> + * B0 -> B1 + * ... + * v0|i = ... + * JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1 + * ________________________________________________ + * + * B2 -> B1 + * ... + * v1|i = ... + * v2|i = ... + * JUMP ~[v1|i, v2|i] destination: B2 -> B1 + * ________________________________________________ + * + * B1 <- B0,B2 + * [v3|i, v4|i] = LABEL + * ... + * </pre> + */ +public final class SSAUtil { + + public interface PhiValueVisitor { + /** + * @param phiIn the incoming value at the merge block + * @param phiOut the outgoing value from the predecessor block + */ + void visit(Value phiIn, Value phiOut); + } + + /** + * Visits each phi value pair of an edge, i.e. the outgoing value from the predecessor and the + * incoming value to the merge block. + */ + public static void forEachPhiValuePair(LIR lir, AbstractBlockBase<?> merge, AbstractBlockBase<?> pred, PhiValueVisitor visitor) { + if (merge.getPredecessorCount() < 2) { + return; + } + assert merge.getPredecessors().contains(pred) : String.format("%s not in predecessor list: %s", pred, merge.getPredecessors()); + assert pred.getSuccessorCount() == 1 : String.format("Merge predecessor block %s has more than one successor? %s", pred, pred.getSuccessors()); + assert pred.getSuccessors().get(0) == merge : String.format("Predecessor block %s has wrong successor: %s, should be: %s", pred, pred.getSuccessors().get(0), merge); + + JumpOp jump = phiOut(lir, pred); + LabelOp label = phiIn(lir, merge); + + assert label.getIncomingSize() == jump.getOutgoingSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getIncomingSize(), jump.getOutgoingSize()); + + for (int i = 0; i < label.getIncomingSize(); i++) { + visitor.visit(label.getIncomingValue(i), jump.getOutgoingValue(i)); + } + } + + private static JumpOp phiOut(LIR lir, AbstractBlockBase<?> block) { + assert block.getSuccessorCount() == 1; + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + int index = instructions.size() - 1; + LIRInstruction op = instructions.get(index); + return (JumpOp) op; + } + + public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) { + assert block.getSuccessorCount() == 1; + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + int index = instructions.size() - 1; + assert instructions.get(index) instanceof JumpOp; + return index; + } + + private static LabelOp phiIn(LIR lir, AbstractBlockBase<?> block) { + assert block.getPredecessorCount() > 1; + LabelOp label = (LabelOp) lir.getLIRforBlock(block).get(0); + return label; + } + + public static void removePhiOut(LIR lir, AbstractBlockBase<?> block) { + JumpOp jump = phiOut(lir, block); + jump.clearOutgoingValues(); + } + + public static void removePhiIn(LIR lir, AbstractBlockBase<?> block) { + LabelOp label = phiIn(lir, block); + label.clearIncomingValues(); + } + + public static boolean verifySSAForm(LIR lir) { + return new SSAVerifier(lir).verify(); + } + + public static void verifyPhi(LIR lir, AbstractBlockBase<?> merge) { + assert merge.getPredecessorCount() > 1; + for (AbstractBlockBase<?> pred : merge.getPredecessors()) { + forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> { + assert phiIn.getLIRKind().equals(phiOut.getLIRKind()) || + (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isUnknownReference() && phiOut.getLIRKind().isValue()); + }); + } + } + + public static void forEachPhiRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) { + assert mode == OperandMode.DEF : "Wrong operand mode: " + mode; + assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label); + + if (!label.isPhiIn()) { + return; + } + int idx = indexOfValue(label, targetValue); + assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label); + + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + JumpOp jump = phiOut(lir, pred); + Value sourceValue = jump.getOutgoingValue(idx); + valueConsumer.visitValue(jump, sourceValue, null, null); + } + + } + + private static int indexOfValue(LabelOp label, Value value) { + for (int i = 0; i < label.getIncomingSize(); i++) { + if (label.getIncomingValue(i).equals(value)) { + return i; + } + } + return -1; + } + +}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssa/SSAUtils.java Tue Jul 28 17:35:49 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * 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.lir.ssa; - -import java.util.*; - -import jdk.internal.jvmci.meta.*; - -import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.OperandMode; -import com.oracle.graal.lir.StandardOp.BlockEndOp; -import com.oracle.graal.lir.StandardOp.JumpOp; -import com.oracle.graal.lir.StandardOp.LabelOp; - -/** - * Utilities for working with Static-Single-Assignment LIR form. - * - * <h2>Representation of <code>PHI</code>s</h2> - * - * There is no explicit <code>PHI</code> {@linkplain LIRInstruction}. Instead, they are implemented - * as parallel copy that span across a control-flow edge. - * - * The variables introduced by <code>PHI</code>s of a specific {@linkplain AbstractBlockBase merge - * block} are {@linkplain LabelOp#setIncomingValues attached} to the {@linkplain LabelOp} of the - * block. The outgoing values from the predecessor are {@link JumpOp#setOutgoingValues input} to the - * {@linkplain BlockEndOp} of the predecessor. Because there are no critical edges we know that the - * {@link BlockEndOp} of the predecessor has to be a {@link JumpOp}. - * - * <h3>Example:</h3> - * - * <pre> - * B0 -> B1 - * ... - * v0|i = ... - * JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1 - * ________________________________________________ - * - * B2 -> B1 - * ... - * v1|i = ... - * v2|i = ... - * JUMP ~[v1|i, v2|i] destination: B2 -> B1 - * ________________________________________________ - * - * B1 <- B0,B2 - * [v3|i, v4|i] = LABEL - * ... - * </pre> - */ -public final class SSAUtils { - - public interface PhiValueVisitor { - /** - * @param phiIn the incoming value at the merge block - * @param phiOut the outgoing value from the predecessor block - */ - void visit(Value phiIn, Value phiOut); - } - - /** - * Visits each phi value pair of an edge, i.e. the outgoing value from the predecessor and the - * incoming value to the merge block. - */ - public static void forEachPhiValuePair(LIR lir, AbstractBlockBase<?> merge, AbstractBlockBase<?> pred, PhiValueVisitor visitor) { - if (merge.getPredecessorCount() < 2) { - return; - } - assert merge.getPredecessors().contains(pred) : String.format("%s not in predecessor list: %s", pred, merge.getPredecessors()); - assert pred.getSuccessorCount() == 1 : String.format("Merge predecessor block %s has more than one successor? %s", pred, pred.getSuccessors()); - assert pred.getSuccessors().get(0) == merge : String.format("Predecessor block %s has wrong successor: %s, should be: %s", pred, pred.getSuccessors().get(0), merge); - - JumpOp jump = phiOut(lir, pred); - LabelOp label = phiIn(lir, merge); - - assert label.getIncomingSize() == jump.getOutgoingSize() : String.format("Phi In/Out size mismatch: in=%d vs. out=%d", label.getIncomingSize(), jump.getOutgoingSize()); - - for (int i = 0; i < label.getIncomingSize(); i++) { - visitor.visit(label.getIncomingValue(i), jump.getOutgoingValue(i)); - } - } - - private static JumpOp phiOut(LIR lir, AbstractBlockBase<?> block) { - assert block.getSuccessorCount() == 1; - List<LIRInstruction> instructions = lir.getLIRforBlock(block); - int index = instructions.size() - 1; - LIRInstruction op = instructions.get(index); - return (JumpOp) op; - } - - public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) { - assert block.getSuccessorCount() == 1; - List<LIRInstruction> instructions = lir.getLIRforBlock(block); - int index = instructions.size() - 1; - assert instructions.get(index) instanceof JumpOp; - return index; - } - - private static LabelOp phiIn(LIR lir, AbstractBlockBase<?> block) { - assert block.getPredecessorCount() > 1; - LabelOp label = (LabelOp) lir.getLIRforBlock(block).get(0); - return label; - } - - public static void removePhiOut(LIR lir, AbstractBlockBase<?> block) { - JumpOp jump = phiOut(lir, block); - jump.clearOutgoingValues(); - } - - public static void removePhiIn(LIR lir, AbstractBlockBase<?> block) { - LabelOp label = phiIn(lir, block); - label.clearIncomingValues(); - } - - public static boolean verifySSAForm(LIR lir) { - return new SSAVerifier(lir).verify(); - } - - public static void verifyPhi(LIR lir, AbstractBlockBase<?> merge) { - assert merge.getPredecessorCount() > 1; - for (AbstractBlockBase<?> pred : merge.getPredecessors()) { - forEachPhiValuePair(lir, merge, pred, (phiIn, phiOut) -> { - assert phiIn.getLIRKind().equals(phiOut.getLIRKind()) || - (phiIn.getPlatformKind().equals(phiOut.getPlatformKind()) && phiIn.getLIRKind().isUnknownReference() && phiOut.getLIRKind().isValue()); - }); - } - } - - public static void forEachPhiRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) { - assert mode == OperandMode.DEF : "Wrong operand mode: " + mode; - assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label); - - if (!label.isPhiIn()) { - return; - } - int idx = indexOfValue(label, targetValue); - assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label); - - for (AbstractBlockBase<?> pred : block.getPredecessors()) { - JumpOp jump = phiOut(lir, pred); - Value sourceValue = jump.getOutgoingValue(idx); - valueConsumer.visitValue(jump, sourceValue, null, null); - } - - } - - private static int indexOfValue(LabelOp label, Value value) { - for (int i = 0; i < label.getIncomingSize(); i++) { - if (label.getIncomingValue(i).equals(value)) { - return i; - } - } - return -1; - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIBlockValueMapImpl.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,261 @@ +/* + * 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.lir.ssi; + +import static com.oracle.graal.lir.LIRValueUtil.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.util.*; + +public final class SSIBlockValueMapImpl implements BlockValueMap { + + private static final class BlockData { + + /** Mapping from value to index into {@link #incoming}. */ + private final ValueMap<Value, Integer> valueIndexMap; + private final ArrayList<Value> incoming; + private final ArrayList<Value> outgoing; + + private BlockData(int initialVariableCapacity, int initialStackSlotCapacity) { + valueIndexMap = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity); + incoming = new ArrayList<>(); + outgoing = new ArrayList<>(); + } + + public Integer getIndex(Value operand) { + return valueIndexMap.get(operand); + } + + public Value getIncoming(int index) { + return incoming.get(index); + } + + public void setIncoming(int index, Value value) { + incoming.set(index, value); + } + + public int addIncoming(Value operand) { + assert isVariable(operand) || isVirtualStackSlot(operand) : "Not a variable or vstack: " + operand; + int index = incoming.size(); + incoming.add(Value.ILLEGAL); + valueIndexMap.put(operand, index); + return index; + } + + public boolean contains(Value operand) { + return getIndex(operand) != null; + } + + public int addOutgoing(Value operand) { + int index = outgoing.size(); + outgoing.add(operand); + return index; + } + + } + + /** Mapping from value to definition block. */ + private final ValueMap<Value, AbstractBlockBase<?>> valueToDefBlock; + private final BlockMap<BlockData> blockData; + private final int initialVariableCapacity; + private final int initialStackSlotCapacity; + + public SSIBlockValueMapImpl(AbstractControlFlowGraph<?> cfg, int initialVariableCapacity, int initialStackSlotCapacity) { + this.initialVariableCapacity = initialVariableCapacity; + this.initialStackSlotCapacity = initialStackSlotCapacity; + valueToDefBlock = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity); + blockData = new BlockMap<>(cfg); + } + + @Override + public void accessOperand(Value operand, AbstractBlockBase<?> block) { + assert block != null : "block is null"; + if (operand instanceof CompositeValue) { + ((CompositeValue) operand).forEachComponent(null, OperandMode.USE, (op, value, mode, flag) -> { + accessOperand(value, block); + return value; + }); + } else if (processValue(operand)) { + AbstractBlockBase<?> defBlock = getDefinitionBlock(operand); + assert defBlock != null : "Value is not defined: " + operand; + assert AbstractControlFlowGraph.dominates(defBlock, block) : "Block " + defBlock + " does not dominate " + block; + accessRecursive(operand, defBlock, block); + } + } + + @Override + public void defineOperand(Value operand, AbstractBlockBase<?> block) { + assert block != null : "block is null"; + if (processValue(operand)) { + AbstractBlockBase<?> defBlock = getDefinitionBlock(operand); + if (defBlock == null) { + setDefinitionBlock(operand, block); + } else { + /* + * Redefinition: this can happen for nodes that do not produce a new value but proxy + * another one (PiNode, reinterpret). + */ + assert AbstractControlFlowGraph.dominates(defBlock, block) : String.format("Definition of %s in %s does not dominate the redefinition %s", operand, defBlock, block); + } + } + } + + private static boolean processValue(Value operand) { + return isVariable(operand) || isVirtualStackSlot(operand); + } + + // setter getter for internal data structures + + private AbstractBlockBase<?> getDefinitionBlock(Value operand) { + return valueToDefBlock.get(operand); + } + + private void setDefinitionBlock(Value operand, AbstractBlockBase<?> block) { + valueToDefBlock.put(operand, block); + } + + private BlockData getOrInit(AbstractBlockBase<?> block) { + BlockData data = blockData.get(block); + if (data == null) { + data = new BlockData(initialVariableCapacity, initialStackSlotCapacity); + blockData.put(block, data); + } + return data; + } + + // implementation + + private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block) { + Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>(); + worklist.add(block); + + while (!worklist.isEmpty()) { + accessRecursive(operand, defBlock, worklist.pollLast(), worklist); + } + } + + private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) { + try (Indent indent = Debug.logAndIndent("get operand %s in block %s", operand, block)) { + if (block.equals(defBlock)) { + Debug.log("found definition!"); + return; + } + BlockData data = getOrInit(block); + Integer index = data.getIndex(operand); + if (index != null) { + // value is live at block begin but might not be initialized + Value in = data.getIncoming(index); + if (Value.ILLEGAL.equals(in)) { + data.setIncoming(index, operand); + Debug.log("uninitialized incoming value -> initialize!"); + } else { + Debug.log("incoming value already initialized!"); + } + return; + } + + // the value is not yet live a current block + int idx = addLiveValueToBlock(operand, block); + data.setIncoming(idx, operand); + + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + worklist.addLast(pred); + } + } + } + + private int addLiveValueToBlock(Value operand, AbstractBlockBase<?> block) { + try (Indent indent = Debug.logAndIndent("add incoming value!")) { + int index = -1; + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + try (Indent indent1 = Debug.logAndIndent("Add outgoing operand to %s", pred)) { + BlockData predData = getOrInit(pred); + int predIndex = predData.addOutgoing(operand); + + if (index == -1) { + index = predIndex; + } else { + assert predIndex == index; + } + + for (AbstractBlockBase<?> succ : pred.getSuccessors()) { + Debug.log("Add incoming operand to %s", succ); + BlockData succData = getOrInit(succ); + if (!succData.contains(operand)) { + int succIndex = succData.addIncoming(operand); + assert succIndex == predIndex; + } + } + } + } + Debug.log("new index: %d", index); + return index; + } + } + + // finish + + public void finish(LIRGeneratorTool gen) { + Debug.dump(gen.getResult().getLIR(), "Before SSI operands"); + AbstractControlFlowGraph<?> cfg = gen.getResult().getLIR().getControlFlowGraph(); + for (AbstractBlockBase<?> block : cfg.getBlocks()) { + // set label + BlockData data = blockData.get(block); + if (data != null) { + if (data.incoming != null && data.incoming.size() > 0) { + LabelOp label = getLabel(gen, block); + label.addIncomingValues(data.incoming.toArray(new Value[data.incoming.size()])); + } + // set block end + if (data.outgoing != null && data.outgoing.size() > 0) { + BlockEndOp blockEndOp = getBlockEnd(gen, block); + blockEndOp.addOutgoingValues(data.outgoing.toArray(new Value[data.outgoing.size()])); + } + } + } + } + + private static List<LIRInstruction> getLIRforBlock(LIRGeneratorTool gen, AbstractBlockBase<?> block) { + return gen.getResult().getLIR().getLIRforBlock(block); + } + + private static LabelOp getLabel(LIRGeneratorTool gen, AbstractBlockBase<?> block) { + return (LabelOp) getLIRforBlock(gen, block).get(0); + } + + private static BlockEndOp getBlockEnd(LIRGeneratorTool gen, AbstractBlockBase<?> block) { + List<LIRInstruction> instructions = getLIRforBlock(gen, block); + return (BlockEndOp) instructions.get(instructions.size() - 1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIConstructionPhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,120 @@ +/* + * 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.lir.ssi; + +import java.util.*; + +import jdk.internal.jvmci.code.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.lir.ssa.*; + +public final class SSIConstructionPhase extends PreAllocationOptimizationPhase { + + @Override + protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) { + assert SSAUtil.verifySSAForm(lirGenRes.getLIR()); + LIR lir = lirGenRes.getLIR(); + new SSIBuilder(lir, lirGenRes.getFrameMapBuilder()).build(lirGen); + } + + private static final class SSIBuilder { + private final SSIBlockValueMapImpl valueMap; + private final LIR lir; + private final BitSet processed; + + private SSIBuilder(LIR lir, FrameMapBuilder frameMapBuilder) { + this.lir = lir; + valueMap = new SSIBlockValueMapImpl(lir.getControlFlowGraph(), lir.nextVariable(), ((FrameMapBuilderTool) frameMapBuilder).getNumberOfStackSlots()); + processed = new BitSet(lir.getControlFlowGraph().getBlocks().size()); + } + + private void build(LIRGeneratorTool lirGen) { + Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>(lir.getControlFlowGraph().getBlocks()); + while (!worklist.isEmpty()) { + AbstractBlockBase<?> block = worklist.poll(); + if (!processed.get(block.getId())) { + try (Indent indent = Debug.logAndIndent("Try processing Block %s", block)) { + // check predecessors + boolean reschedule = false; + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + if (!processed.get(pred.getId()) && !isLoopBackEdge(pred, block)) { + Debug.log("Schedule predecessor: %s", pred); + worklist.addLast(pred); + reschedule = true; + } + } + if (reschedule) { + Debug.log("Reschedule block %s", block); + worklist.addLast(block); + } else { + processBlock(block); + } + } + } + } + valueMap.finish(lirGen); + } + + public void processBlock(AbstractBlockBase<?> block) { + assert !processed.get(block.getId()) : "Block already processed " + block; + try (Indent indent = Debug.logAndIndent("Process Block %s", block)) { + // track values + ValueConsumer useConsumer = (value, mode, flags) -> { + if (flags.contains(OperandFlag.UNINITIALIZED)) { + AbstractBlockBase<?> startBlock = lir.getControlFlowGraph().getStartBlock(); + Debug.log("Set definition of %s in block %s", value, startBlock); + valueMap.defineOperand(value, startBlock); + } else { + Debug.log("Access %s in block %s", value, block); + valueMap.accessOperand(value, block); + } + }; + ValueConsumer defConsumer = (value, mode, flags) -> { + Debug.log("Set definition of %s in block %s", value, block); + valueMap.defineOperand(value, block); + }; + for (LIRInstruction op : lir.getLIRforBlock(block)) { + // use + op.visitEachInput(useConsumer); + op.visitEachAlive(useConsumer); + op.visitEachState(useConsumer); + // def + op.visitEachTemp(defConsumer); + op.visitEachOutput(defConsumer); + } + processed.set(block.getId()); + } + } + + private static boolean isLoopBackEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) { + return from.isLoopEnd() && to.isLoopHeader() && from.getLoop().equals(to.getLoop()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,191 @@ +/* + * 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.lir.ssi; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.ssa.SSAUtil.*; + +/** + * Utilities for working with Static-Single-Information LIR form. + * + * <h2>Representation of φ and σ</h2> + * + * There are no explicit φ/σ {@link LIRInstruction}s. Instead, they are implemented as + * parallel copy that spans across a control-flow edge. + * + * The variables introduced by φ/σ of a specific {@linkplain AbstractBlockBase block} are + * {@linkplain LabelOp#setIncomingValues attached} to the {@link LabelOp} of the block. The outgoing + * values from the predecessor are {@linkplain BlockEndOp#setOutgoingValues input} to the + * {@link BlockEndOp} of the predecessor. + * + * When it does not matter whether we are talking about a φ or a σ we call the values that + * are defined by a label {@linkplain LabelOp#setIncomingValues incoming} and the values that are + * input to the {@link BlockEndOp} of the predecessor {@linkplain BlockEndOp#setOutgoingValues + * outgoing}. + * + * <h2>Implementation Details</h2> + * + * For our purposes we want a <em>maximal</em> SSI form, which means that all values that are alive + * across basic block boundaries are gated with a φ/σ. In other words the outgoing and + * incoming values of the {@link BlockEndOp} and {@link LabelOp} are equivalent to the live-out and + * live-in set of the corresponding block. + * + * As a side effect variables are local to a block. We reuse the name of the predecessor if they + * represent the same value (i.e. not a real φ definition). + * + * <h2>Examples</h2> + * + * <h3>Merge (φ)</h3> + * + * <pre> + * B0 -> B1 + * ... + * v0|i = ... + * JUMP ~[v0|i, int[0|0x0]] destination: B0 -> B1 + * ________________________________________________ + * + * B2 -> B1 + * ... + * v1|i = ... + * v2|i = ... + * JUMP ~[v1|i, v2|i] destination: B2 -> B1 + * ________________________________________________ + * + * B1 <- B0,B2 + * [v3|i, v4|i] = LABEL + * ... + * </pre> + * + * Note: the outgoing values of a block can contain constants (see <code>B0</code>). + * + * <h3>Split (σ)</h3> + * + * <pre> + * B0 -> B1,B2 + * ... + * v0|i = ... + * v1|i = ... + * v2|i = ... + * TEST (x: v1|i, y: v1|i) + * BRANCH ~[v2|i, v0|j] condition: <, true: B1 false: B2 + * ________________________________________________ + * + * B1 <- B0 + * [-, v0|j] = LABEL + * ... + * ________________________________________________ + * + * B2 <- B0 + * [v2|i, v0|j] = LABEL + * ... + * </pre> + * + * Note: If a incoming value is not needed in a branch it is {@link Value#ILLEGAL ignored} (see + * <code>B1<code>). + */ +public final class SSIUtil { + + public static BlockEndOp outgoing(LIR lir, AbstractBlockBase<?> block) { + return (BlockEndOp) outgoingInst(lir, block); + } + + public static LIRInstruction outgoingInst(LIR lir, AbstractBlockBase<?> block) { + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + int index = instructions.size() - 1; + LIRInstruction op = instructions.get(index); + return op; + } + + public static LabelOp incoming(LIR lir, AbstractBlockBase<?> block) { + return (LabelOp) incomingInst(lir, block); + } + + private static LIRInstruction incomingInst(LIR lir, AbstractBlockBase<?> block) { + return lir.getLIRforBlock(block).get(0); + } + + public static void removeIncoming(LIR lir, AbstractBlockBase<?> block) { + incoming(lir, block).clearIncomingValues(); + } + + public static void removeOutgoing(LIR lir, AbstractBlockBase<?> block) { + outgoing(lir, block).clearOutgoingValues(); + } + + /** + * Visits each SIGMA/PHI value pair of an edge, i.e. the outgoing value from the predecessor and + * the incoming value to the merge block. + */ + public static void forEachValuePair(LIR lir, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> fromBlock, PhiValueVisitor visitor) { + assert toBlock.getPredecessors().contains(fromBlock) : String.format("%s not in predecessor list: %s", fromBlock, toBlock.getPredecessors()); + assert fromBlock.getSuccessorCount() == 1 || toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s has %d successors and %s has %d predecessors", fromBlock, + fromBlock.getSuccessorCount(), toBlock, toBlock.getPredecessorCount()); + assert fromBlock.getSuccessors().contains(toBlock) : String.format("Predecessor block %s has wrong successor: %s, should contain: %s", fromBlock, fromBlock.getSuccessors(), toBlock); + + BlockEndOp blockEnd = outgoing(lir, fromBlock); + LabelOp label = incoming(lir, toBlock); + + assert label.getIncomingSize() == blockEnd.getOutgoingSize() : String.format("In/Out size mismatch: in=%d vs. out=%d, blocks %s vs. %s", label.getIncomingSize(), blockEnd.getOutgoingSize(), + toBlock, fromBlock); + + for (int i = 0; i < label.getIncomingSize(); i++) { + visitor.visit(label.getIncomingValue(i), blockEnd.getOutgoingValue(i)); + } + } + + public static void forEachRegisterHint(LIR lir, AbstractBlockBase<?> block, LabelOp label, Value targetValue, OperandMode mode, ValueConsumer valueConsumer) { + assert mode == OperandMode.DEF : "Wrong operand mode: " + mode; + assert lir.getLIRforBlock(block).get(0).equals(label) : String.format("Block %s and Label %s do not match!", block, label); + + if (!label.isPhiIn()) { + return; + } + int idx = indexOfValue(label, targetValue); + assert idx >= 0 : String.format("Value %s not in label %s", targetValue, label); + + for (AbstractBlockBase<?> pred : block.getPredecessors()) { + BlockEndOp blockEnd = outgoing(lir, pred); + Value sourceValue = blockEnd.getOutgoingValue(idx); + valueConsumer.visitValue((LIRInstruction) blockEnd, sourceValue, null, null); + } + + } + + private static int indexOfValue(LabelOp label, Value value) { + for (int i = 0; i < label.getIncomingSize(); i++) { + if (label.getIncomingValue(i).equals(value)) { + return i; + } + } + return -1; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ssi/SSIVerifier.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,158 @@ +/* + * 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.lir.ssi; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; + +public final class SSIVerifier { + + public static boolean verify(LIR lir) { + return new SSIVerifier(lir).verify(); + } + + private final LIR lir; + + private SSIVerifier(LIR lir) { + this.lir = lir; + } + + private boolean verify() { + try (Scope s = Debug.scope("SSIVerifier", lir)) { + for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) { + doBlock(block); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + return true; + } + + private void doBlock(AbstractBlockBase<?> block) { + for (AbstractBlockBase<?> succ : block.getSuccessors()) { + verifyEdge(block, succ); + } + verifyInstructions(block); + } + + private void verifyEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) { + BlockEndOp out = SSIUtil.outgoing(lir, from); + LabelOp in = SSIUtil.incoming(lir, to); + int outgoingSize = out.getOutgoingSize(); + int incomingSize = in.getIncomingSize(); + assert outgoingSize == incomingSize : String.format("Outgoing size %d and incoming size %d do not match", outgoingSize, incomingSize); + + for (int i = 0; i < outgoingSize; i++) { + Value incomingValue = in.getIncomingValue(i); + Value outgoingValue = out.getOutgoingValue(i); + LIRKind inLIRKind = incomingValue.getLIRKind(); + LIRKind outLIRKind = outgoingValue.getLIRKind(); + assert LIRKind.verifyMoveKinds(inLIRKind, outLIRKind) || incomingValue.equals(Value.ILLEGAL) : String.format("Outgoing LIRKind %s (%s) an and incoming LIRKind %s (%s) do not match", + outgoingValue, outLIRKind, incomingValue, inLIRKind); + } + } + + private void verifyInstructions(AbstractBlockBase<?> block) { + List<LIRInstruction> instructions = lir.getLIRforBlock(block); + HashMap<Value, LIRInstruction> defined = new HashMap<>(); + + InstructionValueConsumer useConsumer = new InstructionValueConsumer() { + public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { + if (checkUsage(value)) { + assert defined.containsKey(value) || flags.contains(OperandFlag.UNINITIALIZED) : String.format("Value %s is used by instruction %s in block %s but not defined.", value, + instruction, block); + } + } + }; + InstructionValueConsumer stateConsumer = new InstructionValueConsumer() { + public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { + if (checkUsage(value)) { + /* + * TODO (je): There are undefined stack values used for locks. Ignore them for + * the time being. + */ + assert defined.containsKey(value) || isVirtualStackSlot(value) : String.format("Value %s is used in state of instruction %s in block %s but not defined.", value, instruction, + block); + } + } + }; + + InstructionValueConsumer defConsumer = new InstructionValueConsumer() { + public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { + if (trackDefinition(value)) { + assert !defined.containsKey(value) : String.format("Value %s is redefined by instruction %s in block %s but already defined by %s.", value, instruction, block, defined.get(value)); + defined.put(value, instruction); + } + } + }; + + for (LIRInstruction op : instructions) { + op.visitEachAlive(useConsumer); + op.visitEachInput(useConsumer); + op.visitEachState(stateConsumer); + + op.visitEachTemp(defConsumer); + op.visitEachOutput(defConsumer); + } + } + + private static boolean trackDefinition(Value value) { + if (isRegister(value)) { + // registers can be redefined + return false; + } + if (value.equals(Value.ILLEGAL)) { + // Don't care about illegal values + return false; + } + return true; + } + + private static boolean checkUsage(Value value) { + if (value instanceof Constant) { + // Constants do not need to be defined + return false; + } + if (isRegister(value)) { + // Assume fixed registers are correct + return false; + } + if (value.equals(Value.ILLEGAL)) { + // Don't care about illegal values + return false; + } + return true; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/GenericValueMap.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,54 @@ +/* + * 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.lir.util; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.*; + +public final class GenericValueMap<T> extends ValueMap<Value, T> { + + private final Map<Value, T> data; + + public GenericValueMap() { + data = CollectionsFactory.newMap(); + } + + @Override + public T get(Value value) { + return data.get(value); + } + + @Override + public void remove(Value value) { + data.remove(value); + } + + @Override + public void put(Value value, T object) { + data.put(value, object); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/IndexedValueMap.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,163 @@ +/* + * 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.lir.util; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; + +public final class IndexedValueMap { + private Value[] values; + + public IndexedValueMap() { + values = Value.NO_VALUES; + } + + public IndexedValueMap(IndexedValueMap other) { + int limit = other.values.length; + while (limit > 0) { + if (other.values[limit - 1] == null) { + limit--; + continue; + } + break; + } + values = new Value[limit]; + System.arraycopy(other.values, 0, values, 0, values.length); + } + + public Value get(int index) { + return values[index]; + } + + public void put(int index, Value value) { + if (values.length <= index) { + if (value == null) { + return; + } + Value[] newValues = new Value[index + 1]; + System.arraycopy(values, 0, newValues, 0, values.length); + values = newValues; + values[index] = value; + } else { + values[index] = value; + } + } + + public void putAll(IndexedValueMap stack) { + Value[] otherValues = stack.values; + int limit = otherValues.length; + if (limit > values.length) { + while (limit > 0) { + if (otherValues[limit - 1] == null) { + limit--; + continue; + } + break; + } + if (limit > values.length) { + Value[] newValues = new Value[limit]; + System.arraycopy(values, 0, newValues, 0, values.length); + values = newValues; + } + } + for (int i = 0; i < limit; i++) { + Value value = otherValues[i]; + if (value != null) { + values[i] = value; + } + } + } + + @Override + public boolean equals(Object other) { + if (other instanceof IndexedValueMap) { + IndexedValueMap that = (IndexedValueMap) other; + int limit = Math.min(values.length, that.values.length); + for (int i = 0; i < limit; i++) { + if (!Objects.equals(values[i], that.values[i])) { + return false; + } + } + for (int i = limit; i < values.length; i++) { + if (values[i] != null) { + return false; + } + } + for (int i = limit; i < that.values.length; i++) { + if (that.values[i] != null) { + return false; + } + } + return true; + } + return false; + } + + public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueProcedure proc) { + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + values[i] = proc.doValue(inst, values[i], mode, flags); + } + } + } + + public void forEach(LIRInstruction inst, OperandMode mode, EnumSet<OperandFlag> flags, InstructionValueConsumer consumer) { + for (Value v : values) { + if (v != null) { + consumer.visitValue(inst, v, mode, flags); + } + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("["); + boolean comma = false; + + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + if (comma) { + sb.append(", "); + } else { + comma = true; + } + + sb.append(i); + sb.append(": "); + sb.append(values[i]); + } + } + sb.append(']'); + return sb.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueMap.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,46 @@ +/* + * 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.lir.util; + +import jdk.internal.jvmci.meta.*; + +/** + * A map interface to map {@link Value}s to other objects. + */ +public abstract class ValueMap<K extends Value, T> { + + /** + * Gets the object associated with {@code value} or {@code null} if there is no such mapping. + */ + public abstract T get(K value); + + /** + * Removes the object associated with {@code value} from the map. + */ + public abstract void remove(K value); + + /** + * Associates {@code object} with {@code value}. + */ + public abstract void put(K value, T object); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/ValueSet.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,36 @@ +/* + * 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.lir.util; + +import jdk.internal.jvmci.meta.*; + +public abstract class ValueSet<S extends ValueSet<S>> { + + public abstract void put(Value v); + + public abstract void remove(Value v); + + public abstract void putAll(S s); + + public abstract S copy(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/util/VariableVirtualStackValueMap.java Wed Jul 29 11:59:18 2015 +0200 @@ -0,0 +1,98 @@ +/* + * 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.lir.util; + +import static com.oracle.graal.lir.LIRValueUtil.*; +import static jdk.internal.jvmci.code.ValueUtil.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +public class VariableVirtualStackValueMap<K extends Value, T> extends ValueMap<K, T> { + + private final Object[] variables; + private final Object[] slots; + + public VariableVirtualStackValueMap(int initialVariableCapacity, int initialStackSlotCapacity) { + variables = new Object[initialVariableCapacity]; + slots = new Object[initialStackSlotCapacity]; + } + + @Override + public T get(K value) { + if (isVariable(value)) { + return get(variables, asVariable(value).index); + } + if (isVirtualStackSlot(value)) { + return get(slots, asVirtualStackSlot(value).getId()); + } + throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value); + } + + @Override + public void remove(K value) { + if (isVariable(value)) { + remove(variables, asVariable(value).index); + } else if (isVirtualStackSlot(value)) { + remove(slots, asVirtualStackSlot(value).getId()); + } else { + throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value); + } + } + + @Override + public void put(K value, T object) { + if (isVariable(value)) { + put(variables, asVariable(value).index, object); + } else if (isVirtualStackSlot(value)) { + put(slots, asVirtualStackSlot(value).getId(), object); + } else { + throw JVMCIError.shouldNotReachHere("Unsupported Value: " + value); + } + } + + @SuppressWarnings("unchecked") + private static <T> T get(Object[] array, int index) { + if (index >= array.length) { + return null; + } + return (T) array[index]; + } + + private static void remove(Object[] array, int index) { + if (index >= array.length) { + return; + } + array[index] = null; + } + + private static <T> Object[] put(Object[] array, int index, T object) { + if (index >= array.length) { + Object[] newArray = new Object[index + 1]; + System.arraycopy(array, 0, newArray, 0, array.length); + newArray[index] = object; + return newArray; + } + array[index] = object; + return null; + } +}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode @@ -72,9 +73,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + tool.replaceWithVirtual((VirtualObjectNode) alias); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * A node that changes the type of its input, usually narrowing it. For example, a {@link PiNode} @@ -90,9 +91,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) { + tool.replaceWithVirtual(virtual); + } } } @@ -107,18 +111,15 @@ return object(); } if (getGuard() != null) { - for (Node use : getGuard().asNode().usages()) { - if (use instanceof PiNode) { - PiNode otherPi = (PiNode) use; - if (object() == otherPi.object() && stamp().equals(otherPi.stamp())) { - /* - * Two PiNodes with the same guard and same result, so return the one with - * the more precise piStamp. - */ - Stamp newStamp = piStamp.join(otherPi.piStamp); - if (newStamp.equals(otherPi.piStamp)) { - return otherPi; - } + for (PiNode otherPi : getGuard().asNode().usages().filter(PiNode.class)) { + if (object() == otherPi.object() && stamp().equals(otherPi.stamp())) { + /* + * Two PiNodes with the same guard and same result, so return the one with the + * more precise piStamp. + */ + Stamp newStamp = piStamp.join(otherPi.piStamp); + if (newStamp.equals(otherPi.piStamp)) { + return otherPi; } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed Jul 29 11:59:18 2015 +0200 @@ -42,7 +42,7 @@ * A graph that contains at least one distinguished node : the {@link #start() start} node. This * node is the start of the control flow of the graph. */ -public class StructuredGraph extends Graph implements JavaMethodContex { +public class StructuredGraph extends Graph implements JavaMethodContext { /** * The different stages of the compilation of a {@link Graph} regarding the status of
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo(nameTemplate = "Proxy({i#value})") public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy { @@ -58,9 +59,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(value); + if (alias instanceof VirtualObjectNode) { + tool.replaceWithVirtual((VirtualObjectNode) alias); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -68,8 +68,10 @@ @Override public void virtualize(VirtualizerTool tool) { - if (tool.getObjectState(getValue()) != null) { - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState fold = tryFold(alias.stamp()); + if (fold != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph())); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo(shortName = "==") public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable { @@ -71,13 +72,13 @@ return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored); } - private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) { - if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) { + private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) { + if (!virtual.hasIdentity() && virtual.entryKind(0) == Kind.Boolean) { if (other.isConstant()) { JavaConstant otherUnboxed = tool.getConstantReflectionProvider().unboxPrimitive(other.asJavaConstant()); if (otherUnboxed != null && otherUnboxed.getKind() == Kind.Boolean) { int expectedValue = otherUnboxed.asBoolean() ? 1 : 0; - IntegerEqualsNode equals = new IntegerEqualsNode(state.getEntry(0), ConstantNode.forInt(expectedValue, graph())); + IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(virtual, 0), ConstantNode.forInt(expectedValue, graph())); tool.addNode(equals); tool.replaceWithValue(equals); } else { @@ -92,43 +93,42 @@ @Override public void virtualize(VirtualizerTool tool) { - State stateX = tool.getObjectState(getX()); - State stateY = tool.getObjectState(getY()); - boolean xVirtual = stateX != null && stateX.getState() == EscapeState.Virtual; - boolean yVirtual = stateY != null && stateY.getState() == EscapeState.Virtual; + ValueNode xAlias = tool.getAlias(getX()); + ValueNode yAlias = tool.getAlias(getY()); + + VirtualObjectNode xVirtual = xAlias instanceof VirtualObjectNode ? (VirtualObjectNode) xAlias : null; + VirtualObjectNode yVirtual = yAlias instanceof VirtualObjectNode ? (VirtualObjectNode) yAlias : null; - if (xVirtual && !yVirtual) { - virtualizeNonVirtualComparison(stateX, stateY != null ? stateY.getMaterializedValue() : getY(), tool); - } else if (!xVirtual && yVirtual) { - virtualizeNonVirtualComparison(stateY, stateX != null ? stateX.getMaterializedValue() : getX(), tool); - } else if (xVirtual && yVirtual) { - boolean xIdentity = stateX.getVirtualObject().hasIdentity(); - boolean yIdentity = stateY.getVirtualObject().hasIdentity(); - if (xIdentity ^ yIdentity) { + if (xVirtual != null && yVirtual == null) { + virtualizeNonVirtualComparison(xVirtual, yAlias, tool); + } else if (xVirtual == null && yVirtual != null) { + virtualizeNonVirtualComparison(yVirtual, xAlias, tool); + } else if (xVirtual != null && yVirtual != null) { + if (xVirtual.hasIdentity() ^ yVirtual.hasIdentity()) { /* * One of the two objects has identity, the other doesn't. In code, this looks like * "Integer.valueOf(a) == new Integer(b)", which is always false. - * + * * In other words: an object created via valueOf can never be equal to one created * by new in the same compilation unit. */ tool.replaceWithValue(LogicConstantNode.contradiction(graph())); - } else if (!xIdentity && !yIdentity) { - ResolvedJavaType type = stateX.getVirtualObject().type(); - if (type.equals(stateY.getVirtualObject().type())) { + } else if (!xVirtual.hasIdentity() && !yVirtual.hasIdentity()) { + ResolvedJavaType type = xVirtual.type(); + if (type.equals(yVirtual.type())) { MetaAccessProvider metaAccess = tool.getMetaAccessProvider(); if (type.equals(metaAccess.lookupJavaType(Integer.class)) || type.equals(metaAccess.lookupJavaType(Long.class))) { // both are virtual without identity: check contents - assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1; - assert stateX.getVirtualObject().entryKind(0).getStackKind() == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long; - IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0)); + assert xVirtual.entryCount() == 1 && yVirtual.entryCount() == 1; + assert xVirtual.entryKind(0).getStackKind() == Kind.Int || xVirtual.entryKind(0) == Kind.Long; + IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0)); tool.addNode(equals); tool.replaceWithValue(equals); } } } else { // both are virtual with identity: check if they refer to the same object - tool.replaceWithValue(LogicConstantNode.forBoolean(stateX == stateY, graph())); + tool.replaceWithValue(LogicConstantNode.forBoolean(xVirtual == yVirtual, graph())); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * This is a special version of the dynamic counter node that removes itself as soon as it's the @@ -55,8 +56,8 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(checkedValue); - if (state != null && state.getState() == EscapeState.Virtual) { + ValueNode alias = tool.getAlias(checkedValue); + if (alias instanceof VirtualObjectNode) { tool.delete(); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -76,13 +76,13 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode v = tool.getReplacedValue(getValue()); + ValueNode alias = tool.getAlias(getValue()); ResolvedJavaType type = StampTool.typeOrNull(stamp()); VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); assert newVirtual.getFields().length == 1; - tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList(), false); + tool.createVirtualObject(newVirtual, new ValueNode[]{alias}, Collections.<MonitorIdNode> emptyList(), false); tool.replaceWithVirtual(newVirtual); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GetClassNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Loads an object's class (i.e., this node can be created for {@code object.getClass()}). @@ -87,9 +88,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null) { - Constant javaClass = state.getVirtualObject().type().getJavaClass(); + ValueNode alias = tool.getAlias(getObject()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + Constant javaClass = virtual.type().getJavaClass(); tool.replaceWithValue(ConstantNode.forConstant(stamp(), javaClass, tool.getMetaAccessProvider(), graph())); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,8 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import jdk.internal.jvmci.meta.Assumptions.AssumptionResult; import jdk.internal.jvmci.meta.*; -import jdk.internal.jvmci.meta.Assumptions.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.*; @@ -116,10 +116,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null) { - Constant constantHub = state.getVirtualObject().type().getObjectHub(); - tool.replaceWithValue(ConstantNode.forConstant(stamp(), constantHub, tool.getMetaAccessProvider(), graph())); + ValueNode alias = tool.getAlias(getValue()); + ResolvedJavaType type = findSynonymType(graph(), tool.getMetaAccessProvider(), alias); + if (type != null) { + tool.replaceWithValue(ConstantNode.forConstant(stamp(), type.getObjectHub(), tool.getMetaAccessProvider(), graph())); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; @NodeInfo public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary<ValueNode> { @@ -68,12 +69,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null && state.getState() == EscapeState.Virtual) { - ResolvedJavaType objectType = state.getVirtualObject().type(); + ValueNode alias = tool.getAlias(getValue()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ResolvedJavaType objectType = virtual.type(); ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass()); if (objectType.equals(expectedType)) { - tool.replaceWithValue(state.getEntry(0)); + tool.replaceWithValue(tool.getEntry(virtual, 0)); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. It @@ -92,9 +93,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual && StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); + ValueNode alias = tool.getAlias(object); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (StampTool.typeOrNull(this) != null && StampTool.typeOrNull(this).isAssignableFrom(virtual.type())) { + tool.replaceWithVirtual(virtual); + } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Load of a value from a location specified as an offset relative to an object. No null check is @@ -60,16 +61,17 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - ValueNode offsetValue = tool.getReplacedValue(offset()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ValueNode offsetValue = tool.getAlias(offset()); if (offsetValue.isConstant()) { long off = offsetValue.asJavaConstant().asLong(); - int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(off, accessKind()); if (entryIndex != -1) { - ValueNode entry = state.getEntry(entryIndex); - Kind entryKind = state.getVirtualObject().entryKind(entryIndex); + ValueNode entry = tool.getEntry(virtual, entryIndex); + Kind entryKind = virtual.entryKind(entryIndex); if (entry.getKind() == getKind() || entryKind == accessKind()) { tool.replaceWith(entry); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * Store of a value at a location specified as an offset relative to an object. No null check is @@ -79,26 +80,27 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(offset()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + ValueNode indexValue = tool.getAlias(offset()); if (indexValue.isConstant()) { long off = indexValue.asJavaConstant().asLong(); - int entryIndex = state.getVirtualObject().entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(off, accessKind()); if (entryIndex != -1) { - Kind entryKind = state.getVirtualObject().entryKind(entryIndex); - ValueNode entry = state.getEntry(entryIndex); + Kind entryKind = virtual.entryKind(entryIndex); + ValueNode entry = tool.getEntry(virtual, entryIndex); if (entry.getKind() == value.getKind() || entryKind == accessKind()) { - tool.setVirtualEntry(state, entryIndex, value(), true); + tool.setVirtualEntry(virtual, entryIndex, value(), true); tool.delete(); } else { if ((accessKind() == Kind.Long || accessKind() == Kind.Double) && entryKind == Kind.Int) { - int nextIndex = state.getVirtualObject().entryIndexForOffset(off + 4, entryKind); + int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind); if (nextIndex != -1) { - Kind nextKind = state.getVirtualObject().entryKind(nextIndex); + Kind nextKind = virtual.entryKind(nextIndex); if (nextKind == Kind.Int) { - tool.setVirtualEntry(state, entryIndex, value(), true); - tool.setVirtualEntry(state, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true); + tool.setVirtualEntry(virtual, entryIndex, value(), true); + tool.setVirtualEntry(virtual, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true); tool.delete(); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; /** * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph. @@ -94,13 +95,14 @@ @Override public void virtualize(VirtualizerTool tool) { - if (anchored != null && !(anchored instanceof AbstractBeginNode)) { - State state = tool.getObjectState(anchored); - if (state == null || state.getState() != EscapeState.Virtual) { - return; + if (anchored == null || anchored instanceof AbstractBeginNode) { + tool.delete(); + } else { + ValueNode alias = tool.getAlias(anchored); + if (alias instanceof VirtualObjectNode) { + tool.delete(); } } - tool.delete(); } public void removeAnchoredNode() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -136,10 +136,14 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(array()); - if (state != null) { - assert state.getVirtualObject().type().isArray(); - tool.replaceWithValue(ConstantNode.forInt(state.getVirtualObject().entryCount(), graph())); + ValueNode alias = tool.getAlias(array()); + ValueNode length = GraphUtil.arrayLength(alias); + if (length != null) { + ValueNode lengthAlias = tool.getAlias(length); + if (!lengthAlias.isAlive()) { + lengthAlias = graph().addOrUnique(lengthAlias); + } + tool.replaceWithValue(lengthAlias); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -240,11 +240,9 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - if (type.isAssignableFrom(state.getVirtualObject().type())) { - tool.replaceWithVirtual(state.getVirtualObject()); - } + ValueNode alias = tool.getAlias(object); + if (tryFold(alias.stamp()) == TriState.TRUE) { + tool.replaceWith(alias); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -164,9 +164,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null) { - tool.replaceWithValue(LogicConstantNode.forBoolean(type().isAssignableFrom(state.getVirtualObject().type()), graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState fold = tryFold(alias.stamp()); + if (fold != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph())); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -121,11 +121,11 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + int fieldIndex = ((VirtualInstanceNode) alias).fieldIndex(field()); if (fieldIndex != -1) { - tool.replaceWith(state.getEntry(fieldIndex)); + tool.replaceWith(tool.getEntry((VirtualObjectNode) alias, fieldIndex)); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code LoadIndexedNode} represents a read from an element of an array. @@ -79,12 +80,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State arrayState = tool.getObjectState(array()); - if (arrayState != null && arrayState.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(index()); + ValueNode alias = tool.getAlias(array()); + if (alias instanceof VirtualObjectNode) { + VirtualArrayNode virtual = (VirtualArrayNode) alias; + ValueNode indexValue = tool.getAlias(index()); int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1; - if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) { - tool.replaceWith(arrayState.getEntry(idx)); + if (idx >= 0 && idx < virtual.entryCount()) { + tool.replaceWith(tool.getEntry(virtual, idx)); } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. @@ -55,10 +56,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - state.addLock(getMonitorId()); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + tool.addLock(virtual, getMonitorId()); + tool.delete(); + } } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of @@ -79,12 +80,15 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); // the monitor exit for a synchronized method should never be virtualized - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - MonitorIdNode removedLock = state.removeLock(); - assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId(); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + MonitorIdNode removedLock = tool.removeLock(virtual); + assert removedLock == getMonitorId() : "mismatch at " + this + ": " + removedLock + " vs. " + getMonitorId(); + tool.delete(); + } } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -74,9 +74,9 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode replacedLength = tool.getReplacedValue(length()); - if (replacedLength.asConstant() != null) { - final int constantLength = replacedLength.asJavaConstant().asInt(); + ValueNode lengthAlias = tool.getAlias(length()); + if (lengthAlias.asConstant() != null) { + int constantLength = lengthAlias.asJavaConstant().asInt(); if (constantLength >= 0 && constantLength < tool.getMaximumEntryCount()) { ValueNode[] state = new ValueNode[constantLength]; ConstantNode defaultForKind = constantLength == 0 ? null : defaultElementValue();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. The object needs already be @@ -61,10 +62,13 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - state.addLock(getMonitorId()); - tool.delete(); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual.hasIdentity()) { + tool.addLock(virtual, getMonitorId()); + tool.delete(); + } } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * This node is used to perform the finalizer registration at the end of the java.lang.Object @@ -94,8 +95,8 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null && !state.getVirtualObject().type().hasFinalizer()) { + ValueNode alias = tool.getAlias(getValue()); + if (alias instanceof VirtualObjectNode && !((VirtualObjectNode) alias).type().hasFinalizer()) { tool.delete(); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -72,11 +72,12 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual) { - int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field()); + ValueNode alias = tool.getAlias(object()); + if (alias instanceof VirtualObjectNode) { + VirtualInstanceNode virtual = (VirtualInstanceNode) alias; + int fieldIndex = virtual.fieldIndex(field()); if (fieldIndex != -1) { - tool.setVirtualEntry(state, fieldIndex, value(), false); + tool.setVirtualEntry(virtual, fieldIndex, value(), false); tool.delete(); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code StoreIndexedNode} represents a write to an array element. @@ -66,15 +67,16 @@ @Override public void virtualize(VirtualizerTool tool) { - State arrayState = tool.getObjectState(array()); - if (arrayState != null && arrayState.getState() == EscapeState.Virtual) { - ValueNode indexValue = tool.getReplacedValue(index()); + ValueNode alias = tool.getAlias(array()); + if (alias instanceof VirtualObjectNode) { + ValueNode indexValue = tool.getAlias(index()); int idx = indexValue.isConstant() ? indexValue.asJavaConstant().asInt() : -1; - if (idx >= 0 && idx < arrayState.getVirtualObject().entryCount()) { - ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType(); + VirtualArrayNode virtual = (VirtualArrayNode) alias; + if (idx >= 0 && idx < virtual.entryCount()) { + ResolvedJavaType componentType = virtual.type().getComponentType(); if (componentType.isPrimitive() || StampTool.isPointerAlwaysNull(value) || componentType.getSuperclass() == null || (StampTool.typeOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) { - tool.setVirtualEntry(arrayState, idx, value(), false); + tool.setVirtualEntry(virtual, idx, value(), false); tool.delete(); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -47,6 +47,7 @@ this.type = type; assert type != null; assert type.isConcrete() || type.isArray(); + assert ((ObjectStamp) object.stamp()).nonNull(); } public static LogicNode create(ResolvedJavaType type, ValueNode object) { @@ -71,7 +72,6 @@ return this; } ObjectStamp objectStamp = (ObjectStamp) forValue.stamp(); - assert objectStamp.nonNull(); ResolvedJavaType stampType = objectStamp.type(); if (stampType != null) { @@ -123,9 +123,10 @@ @Override public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(getValue()); - if (state != null) { - tool.replaceWithValue(LogicConstantNode.forBoolean(type().equals(state.getVirtualObject().type()), graph())); + ValueNode alias = tool.getAlias(getValue()); + TriState state = tryFold(alias.stamp()); + if (state != TriState.UNKNOWN) { + tool.replaceWithValue(LogicConstantNode.forBoolean(state.isTrue(), graph())); } }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,10 +22,6 @@ */ package com.oracle.graal.nodes.spi; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.virtual.*; - /** * This interface allows a node to convey information about what its effect would be if some of its * inputs were virtualized. The {@link #virtualize(VirtualizerTool)} method will only be called for @@ -34,30 +30,6 @@ */ public interface Virtualizable { - public static enum EscapeState { - Virtual, - Materialized - } - - public abstract static class State { - - public abstract EscapeState getState(); - - public abstract VirtualObjectNode getVirtualObject(); - - public abstract ValueNode getEntry(int index); - - public abstract void addLock(MonitorIdNode monitorId); - - public abstract MonitorIdNode removeLock(); - - public abstract ValueNode getMaterializedValue(); - - public abstract void setEnsureVirtualized(boolean ensureVirtualized); - - public abstract boolean getEnsureVirtualized(); - } - /** * A node class can implement this method to convey information about what its effect would be * if some of its inputs were virtualized. All modifications must be made through the supplied
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.virtual.*; /** @@ -72,45 +71,43 @@ void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized); /** - * Queries the current state of the given value: if it is virtualized (thread-local and the - * compiler knows all entries) or not. + * Returns a VirtualObjectNode if the given value is aliased with a virtual object that is still + * virtual, the materialized value of the given value is aliased with a virtual object that was + * materialized, the replacement if the give value was replaced, otherwise the given value. * - * @param value the value whose state should be queried. - * @return the {@link State} representing the value if it has been virtualized at some point, - * null otherwise. + * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This + * method can be used to determine if a value was replaced by another one (e.g., a load field by + * the loaded value). */ - State getObjectState(ValueNode value); + ValueNode getAlias(ValueNode value); /** * Sets the entry (field or array element) with the given index in the virtualized object. * - * @param state the state. * @param index the index to be set. * @param value the new value for the given index. * @param unsafe if true, then mismatching value {@link Kind}s will be accepted. */ - void setVirtualEntry(State state, int index, ValueNode value, boolean unsafe); + void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, boolean unsafe); - // scalar replacement + ValueNode getEntry(VirtualObjectNode virtualObject, int index); + + void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId); - /** - * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This - * method can be used to determine if a value was replaced by another one (e.g., a load field by - * the loaded value). - * - * @param original the original input value. - * @return the replacement value, or the original value if there is no replacement. - */ - ValueNode getReplacedValue(ValueNode original); + MonitorIdNode removeLock(VirtualObjectNode virtualObject); + + void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized); + + boolean getEnsureVirtualized(VirtualObjectNode virtualObject); // operations on the current node /** * Deletes the current node and replaces it with the given virtualized object. * - * @param virtual the virtualized object that should replace the current node. + * @param virtualObject the virtualized object that should replace the current node. */ - void replaceWithVirtual(VirtualObjectNode virtual); + void replaceWithVirtual(VirtualObjectNode virtualObject); /** * Deletes the current node and replaces it with the given value.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -44,14 +44,15 @@ } public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { - if (state.getVirtualObject() instanceof VirtualBoxingNode) { - Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", state.getVirtualObject().type().getName()); + ValueNode alias = tool.getAlias(object); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + if (virtual instanceof VirtualBoxingNode) { + Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName()); throw GraphUtil.approxSourceException(this, exception); } if (!localOnly) { - state.setEnsureVirtualized(true); + tool.setEnsureVirtualized(virtual, true); } tool.delete(); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -35,12 +35,32 @@ public static final NodeClass<VirtualObjectNode> TYPE = NodeClass.create(VirtualObjectNode.class); protected boolean hasIdentity; + private int objectId = -1; protected VirtualObjectNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType type, boolean hasIdentity) { super(c, StampFactory.exactNonNull(type)); this.hasIdentity = hasIdentity; } + public final int getObjectId() { + return objectId; + } + + public final void resetObjectId() { + this.objectId = -1; + } + + public final void setObjectId(int objectId) { + assert objectId != -1; + this.objectId = objectId; + } + + @Override + protected void afterClone(Node other) { + super.afterClone(other); + resetObjectId(); + } + /** * The type of object described by this {@link VirtualObjectNode}. In case of arrays, this is * the array type (and not the component type).
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,8 +31,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Wed Jul 29 11:59:18 2015 +0200 @@ -543,7 +543,7 @@ } // print use positions - int prev = 0; + int prev = -1; UsePosList usePosList = interval.usePosList(); for (int i = usePosList.size() - 1; i >= 0; --i) { assert prev < usePosList.usePos(i) : "use positions not sorted";
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Wed Jul 29 11:59:18 2015 +0200 @@ -28,14 +28,13 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.service.*; import com.oracle.graal.code.*; +import com.oracle.graal.compiler.common.cfg.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.graph.*; import com.oracle.graal.java.*; @@ -204,6 +203,8 @@ } } else if (object instanceof StackInterval[]) { cfgPrinter.printStackIntervals(message, (StackInterval[]) object); + } else if (isBlockList(object)) { + cfgPrinter.printCFG(message, getBlockList(object), false); } cfgPrinter.target = null; @@ -214,6 +215,15 @@ } + @SuppressWarnings("unchecked") + private static List<? extends AbstractBlockBase<?>> getBlockList(Object object) { + return (List<? extends AbstractBlockBase<?>>) object; + } + + private static boolean isBlockList(Object object) { + return object instanceof List<?> && ((List<?>) object).size() > 0 && ((List<?>) object).get(0) instanceof AbstractBlockBase<?>; + } + private static DisassemblerProvider disassembler; private static final DisassemblerProvider NOP_DISASSEMBLER = new DisassemblerProvider() {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CompilationPrinter.java Wed Jul 29 11:59:18 2015 +0200 @@ -26,10 +26,10 @@ import java.util.*; import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.meta.*; -import com.oracle.graal.lir.dfa.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.util.*; /** * Utility for printing compilation related data structures at various compilation phases. The @@ -114,7 +114,7 @@ /** * Formats given debug info as a multi line string. */ - protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, ValueSet liveBasePointers, RegisterSaveLayout calleeSaveInfo) { + protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) { StringBuilder sb = new StringBuilder(); if (refMap != null) { sb.append("reference-map: ");
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraalDebugConfigCustomizer.java Wed Jul 29 11:59:18 2015 +0200 @@ -26,7 +26,6 @@ import com.oracle.graal.debug.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.service.*; import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Wed Jul 29 11:59:18 2015 +0200 @@ -35,7 +35,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.meta.*; import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Wed Jul 29 11:59:18 2015 +0200 @@ -35,13 +35,6 @@ public @interface Snippet { /** - * Specifies whether all FrameStates within this snippet should always be removed. If this is - * false, FrameStates are only removed if there are no side-effecting instructions in the - * snippet. - */ - boolean removeAllFrameStates() default false; - - /** * Denotes a snippet parameter representing 0 or more arguments that will be bound during * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet * template creation, its value must be an array whose length specifies the number of arguments
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Jul 29 11:59:18 2015 +0200 @@ -22,10 +22,10 @@ */ package com.oracle.graal.replacements; +import static com.oracle.graal.debug.Debug.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.*; import static java.util.FormattableFlags.*; -import static com.oracle.graal.debug.Debug.*; import static jdk.internal.jvmci.meta.LocationIdentity.*; import java.lang.reflect.*; @@ -37,15 +37,12 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; - import jdk.internal.jvmci.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.memory.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; // JaCoCo Exclude @@ -76,32 +77,33 @@ } public void virtualize(VirtualizerTool tool) { - State state1 = tool.getObjectState(array1); - if (state1 != null) { - State state2 = tool.getObjectState(array2); - if (state2 != null) { - if (state1.getVirtualObject() == state2.getVirtualObject()) { - // the same virtual objects will always have the same contents + ValueNode alias1 = tool.getAlias(array1); + ValueNode alias2 = tool.getAlias(array2); + if (alias1 == alias2) { + // the same virtual objects will always have the same contents + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } else if (alias1 instanceof VirtualObjectNode && alias2 instanceof VirtualObjectNode) { + VirtualObjectNode virtual1 = (VirtualObjectNode) alias1; + VirtualObjectNode virtual2 = (VirtualObjectNode) alias2; + + if (virtual1.entryCount() == virtual2.entryCount()) { + int entryCount = virtual1.entryCount(); + boolean allEqual = true; + for (int i = 0; i < entryCount; i++) { + ValueNode entry1 = tool.getEntry(virtual1, i); + ValueNode entry2 = tool.getEntry(virtual2, i); + if (entry1 != entry2) { + // the contents might be different + allEqual = false; + } + if (entry1.stamp().alwaysDistinct(entry2.stamp())) { + // the contents are different + tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); + return; + } + } + if (allEqual) { tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); - } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount() && state1.getState() == EscapeState.Virtual && state2.getState() == EscapeState.Virtual) { - int entryCount = state1.getVirtualObject().entryCount(); - boolean allEqual = true; - for (int i = 0; i < entryCount; i++) { - ValueNode entry1 = state1.getEntry(i); - ValueNode entry2 = state2.getEntry(i); - if (entry1 != entry2) { - // the contents might be different - allEqual = false; - } - if (entry1.stamp().alwaysDistinct(entry2.stamp())) { - // the contents are different - tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); - return; - } - } - if (allEqual) { - tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); - } } } }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -131,21 +131,11 @@ return position >= 0 && position + length <= virtualObject.entryCount(); } - private static boolean checkEntryTypes(int srcPos, int length, State srcState, ResolvedJavaType destComponentType, VirtualizerTool tool) { + private static boolean checkEntryTypes(int srcPos, int length, VirtualObjectNode src, ResolvedJavaType destComponentType, VirtualizerTool tool) { if (destComponentType.getKind() == Kind.Object) { for (int i = 0; i < length; i++) { - ValueNode entry = srcState.getEntry(srcPos + i); - State state = tool.getObjectState(entry); - ResolvedJavaType type; - if (state != null) { - if (state.getState() == EscapeState.Virtual) { - type = state.getVirtualObject().type(); - } else { - type = StampTool.typeOrNull(state.getMaterializedValue()); - } - } else { - type = StampTool.typeOrNull(entry); - } + ValueNode entry = tool.getEntry(src, srcPos + i); + ResolvedJavaType type = StampTool.typeOrNull(entry); if (type == null || !destComponentType.isAssignableFrom(type)) { return false; } @@ -177,52 +167,49 @@ @Override public void virtualize(VirtualizerTool tool) { - ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition()); - ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition()); - ValueNode replacedLength = tool.getReplacedValue(getLength()); + ValueNode sourcePosition = tool.getAlias(getSourcePosition()); + ValueNode destinationPosition = tool.getAlias(getDestinationPosition()); + ValueNode replacedLength = tool.getAlias(getLength()); if (sourcePosition.isConstant() && destinationPosition.isConstant() && replacedLength.isConstant()) { int srcPosInt = sourcePosition.asJavaConstant().asInt(); int destPosInt = destinationPosition.asJavaConstant().asInt(); int len = replacedLength.asJavaConstant().asInt(); - State destState = tool.getObjectState(getDestination()); + ValueNode destAlias = tool.getAlias(getDestination()); - if (destState != null && destState.getState() == EscapeState.Virtual) { - VirtualObjectNode destVirtual = destState.getVirtualObject(); - if (!(destVirtual instanceof VirtualArrayNode)) { - return; - } + if (destAlias instanceof VirtualArrayNode) { + VirtualArrayNode destVirtual = (VirtualArrayNode) destAlias; if (len < 0 || !checkBounds(destPosInt, len, destVirtual)) { return; } - State srcState = tool.getObjectState(getSource()); - if (srcState != null && srcState.getState() == EscapeState.Virtual) { - VirtualObjectNode srcVirtual = srcState.getVirtualObject(); - if (((VirtualArrayNode) destVirtual).componentType().getKind() != Kind.Object) { + ValueNode srcAlias = tool.getAlias(getSource()); + + if (srcAlias instanceof VirtualObjectNode) { + if (!(srcAlias instanceof VirtualArrayNode)) { return; } - if (!(srcVirtual instanceof VirtualArrayNode)) { + VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; + if (destVirtual.componentType().getKind() != Kind.Object) { return; } - if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) { + if (srcVirtual.componentType().getKind() != Kind.Object) { return; } if (!checkBounds(srcPosInt, len, srcVirtual)) { return; } - if (!checkEntryTypes(srcPosInt, len, srcState, destVirtual.type().getComponentType(), tool)) { + if (!checkEntryTypes(srcPosInt, len, srcVirtual, destVirtual.type().getComponentType(), tool)) { return; } for (int i = 0; i < len; i++) { - tool.setVirtualEntry(destState, destPosInt + i, srcState.getEntry(srcPosInt + i), false); + tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false); } tool.delete(); if (Debug.isLogEnabled()) { Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPosInt, getDestination(), destPosInt, len); } } else { - ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue(); - ResolvedJavaType sourceType = StampTool.typeOrNull(source); + ResolvedJavaType sourceType = StampTool.typeOrNull(srcAlias); if (sourceType == null || !sourceType.isArray()) { return; } @@ -232,9 +219,9 @@ return; } for (int i = 0; i < len; i++) { - LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); + LoadIndexedNode load = new LoadIndexedNode(srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getKind()); tool.addNode(load); - tool.setVirtualEntry(destState, destPosInt + i, load, false); + tool.setVirtualEntry(destVirtual, destPosInt + i, load, false); } tool.delete(); }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -90,26 +90,20 @@ @Override public void virtualize(VirtualizerTool tool) { - State originalState = tool.getObjectState(getObject()); - if (originalState != null && originalState.getState() == EscapeState.Virtual) { - VirtualObjectNode originalVirtual = originalState.getVirtualObject(); + ValueNode originalAlias = tool.getAlias(getObject()); + if (originalAlias instanceof VirtualObjectNode) { + VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias; if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; for (int i = 0; i < newEntryState.length; i++) { - newEntryState[i] = originalState.getEntry(i); + newEntryState[i] = tool.getEntry(originalVirtual, i); } VirtualObjectNode newVirtual = originalVirtual.duplicate(); tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false); tool.replaceWithVirtual(newVirtual); } } else { - ValueNode obj; - if (originalState != null) { - obj = originalState.getMaterializedValue(); - } else { - obj = tool.getReplacedValue(getObject()); - } - ResolvedJavaType type = getConcreteType(obj.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider()); + ResolvedJavaType type = getConcreteType(originalAlias.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider()); if (type != null && !type.isArray()) { VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true); ResolvedJavaField[] fields = newVirtual.getFields(); @@ -117,7 +111,7 @@ ValueNode[] state = new ValueNode[fields.length]; final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; for (int i = 0; i < fields.length; i++) { - state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); + state[i] = loads[i] = new LoadFieldNode(originalAlias, fields[i]); tool.addNode(loads[i]); } tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/VirtualizableInvokeMacroNode.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; /** * A helper class to allow elimination of byte code instrumentation that could interfere with escape @@ -46,8 +47,8 @@ @Override public void virtualize(VirtualizerTool tool) { for (ValueNode arg : arguments) { - State state = tool.getObjectState(arg); - if (state != null && state.getState() == EscapeState.Virtual) { + ValueNode alias = tool.getAlias(arg); + if (alias instanceof VirtualObjectNode) { tool.delete(); } }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Wed Jul 29 11:59:18 2015 +0200 @@ -35,7 +35,6 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.code.CallingConvention.Type; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; import jdk.internal.jvmci.hotspot.*; import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.service.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,15 +29,12 @@ import jdk.internal.jvmci.code.*; import jdk.internal.jvmci.code.stack.*; -import jdk.internal.jvmci.debug.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; - import jdk.internal.jvmci.meta.*; import jdk.internal.jvmci.service.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.debug.*; import com.oracle.graal.truffle.unsafe.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedAssumption.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedAssumption.java Wed Jul 29 11:59:18 2015 +0200 @@ -29,8 +29,8 @@ import java.util.stream.*; import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.debug.*; +import com.oracle.graal.debug.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.impl.*;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleDebugJavaMethod.java Wed Jul 29 11:59:18 2015 +0200 @@ -31,7 +31,7 @@ * Enables a Truffle compilable to masquerade as a {@link JavaMethod} for use as a context value in * {@linkplain Debug#scope(Object) debug scopes}. */ -public class TruffleDebugJavaMethod implements JavaMethod, JavaMethodContex { +public class TruffleDebugJavaMethod implements JavaMethod, JavaMethodContext { private final RootCallTarget compilable; private static final JavaType declaringClass = new JavaType() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Jul 29 11:59:18 2015 +0200 @@ -176,8 +176,9 @@ * */ public void replaceAtUsages(ValueNode node, ValueNode replacement) { + assert node != null && replacement != null : node + " " + replacement; add("replace at usages", (graph, obsoleteNodes) -> { - assert node.isAlive() && replacement.isAlive(); + assert node.isAlive() && replacement.isAlive() : node + " " + replacement; if (replacement instanceof FixedWithNextNode && ((FixedWithNextNode) replacement).next() == null) { assert node instanceof FixedNode; graph.addBeforeFixed((FixedNode) node, (FixedWithNextNode) replacement);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Wed Jul 29 11:59:18 2015 +0200 @@ -28,8 +28,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.virtual.nodes.*; @@ -38,14 +36,11 @@ * the fields or array elements (called "entries") and the lock count if the object is still * virtual. If the object was materialized, it contains the current materialized value. */ -public class ObjectState extends Virtualizable.State { +public class ObjectState { public static final DebugMetric CREATE_ESCAPED_OBJECT_STATE = Debug.metric("CreateEscapeObjectState"); public static final DebugMetric GET_ESCAPED_OBJECT_STATE = Debug.metric("GetEscapeObjectState"); - final VirtualObjectNode virtual; - - private EscapeState state; private ValueNode[] entries; private ValueNode materializedValue; private LockState locks; @@ -53,35 +48,32 @@ private EscapeObjectState cachedState; - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks, boolean ensureVirtualized) { - this(virtual, entries, state, (LockState) null, ensureVirtualized); + boolean copyOnWrite; + + public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) { + this(entries, (LockState) null, ensureVirtualized); for (int i = locks.size() - 1; i >= 0; i--) { this.locks = new LockState(locks.get(i), this.locks); } } - public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks, boolean ensureVirtualized) { - this.virtual = virtual; + public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) { this.entries = entries; - this.state = state; this.locks = locks; this.ensureVirtualized = ensureVirtualized; } - public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks, boolean ensureVirtualized) { - this.virtual = virtual; + public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) { + assert materializedValue != null; this.materializedValue = materializedValue; - this.state = state; this.locks = locks; this.ensureVirtualized = ensureVirtualized; } private ObjectState(ObjectState other) { - virtual = other.virtual; entries = other.entries == null ? null : other.entries.clone(); materializedValue = other.materializedValue; locks = other.locks; - state = other.state; cachedState = other.cachedState; ensureVirtualized = other.ensureVirtualized; } @@ -90,7 +82,7 @@ return new ObjectState(this); } - public EscapeObjectState createEscapeObjectState() { + public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) { GET_ESCAPED_OBJECT_STATE.increment(); if (cachedState == null) { CREATE_ESCAPED_OBJECT_STATE.increment(); @@ -100,68 +92,55 @@ } - @Override - public EscapeState getState() { - return state; + public boolean isVirtual() { + assert materializedValue == null ^ entries == null; + return materializedValue == null; } - @Override - public VirtualObjectNode getVirtualObject() { - return virtual; - } - - public boolean isVirtual() { - return state == EscapeState.Virtual; - } - + /** + * Users of this method are not allowed to change the entries of the returned array. + */ public ValueNode[] getEntries() { - assert isVirtual() && entries != null; + assert isVirtual(); return entries; } - @Override public ValueNode getEntry(int index) { assert isVirtual(); return entries[index]; } + public ValueNode getMaterializedValue() { + assert !isVirtual(); + return materializedValue; + } + public void setEntry(int index, ValueNode value) { assert isVirtual(); - if (entries[index] != value) { - cachedState = null; - entries[index] = value; - } + cachedState = null; + entries[index] = value; } - public void escape(ValueNode materialized, EscapeState newState) { - assert state == EscapeState.Virtual && newState == EscapeState.Materialized; - state = newState; + public void escape(ValueNode materialized) { + assert isVirtual(); + assert materialized != null; materializedValue = materialized; entries = null; cachedState = null; assert !isVirtual(); } - @Override - public ValueNode getMaterializedValue() { - assert state == EscapeState.Materialized; - return materializedValue; - } - public void updateMaterializedValue(ValueNode value) { assert !isVirtual(); - if (value != materializedValue) { - cachedState = null; - materializedValue = value; - } + assert value != null; + cachedState = null; + materializedValue = value; } - @Override public void addLock(MonitorIdNode monitorId) { locks = new LockState(monitorId, locks); } - @Override public MonitorIdNode removeLock() { try { return locks.monitorId; @@ -188,12 +167,10 @@ return a == null && b == null; } - @Override public void setEnsureVirtualized(boolean ensureVirtualized) { this.ensureVirtualized = ensureVirtualized; } - @Override public boolean getEnsureVirtualized() { return ensureVirtualized; } @@ -206,7 +183,7 @@ } if (entries != null) { for (int i = 0; i < entries.length; i++) { - str.append(virtual.entryName(i)).append('=').append(entries[i]).append(' '); + str.append("entry").append(i).append('=').append(entries[i]).append(' '); } } if (materializedValue != null) { @@ -223,8 +200,6 @@ result = prime * result + Arrays.hashCode(entries); result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0); result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); - result = prime * result + ((state == null) ? 0 : state.hashCode()); - result = prime * result + ((virtual == null) ? 0 : virtual.hashCode()); return result; } @@ -250,13 +225,11 @@ } else if (!materializedValue.equals(other.materializedValue)) { return false; } - if (state != other.state) { - return false; - } - assert virtual != null && other.virtual != null; - if (!virtual.equals(other.virtual)) { - return false; - } return true; } + + public ObjectState share() { + copyOnWrite = true; + return this; + } }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Wed Jul 29 11:59:18 2015 +0200 @@ -24,16 +24,22 @@ import java.util.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> { - protected final Map<VirtualObjectNode, ObjectState> objectStates = Node.newIdentityMap(); + private static final ObjectState[] EMPTY_ARRAY = new ObjectState[0]; + + private ObjectState[] objectStates; + + private static class RefCount { + private int refCount = 1; + } + + private RefCount arrayRefCount; /** * Final subclass of PartialEscapeBlockState, for performance and to make everything behave @@ -50,32 +56,91 @@ } protected PartialEscapeBlockState() { + objectStates = EMPTY_ARRAY; + arrayRefCount = new RefCount(); } protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) { super(other); - for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) { - objectStates.put(entry.getKey(), entry.getValue().cloneState()); - } + adoptAddObjectStates(other); + } + + public ObjectState getObjectState(int object) { + ObjectState state = objectStates[object]; + assert state != null; + return state; + } + + public ObjectState getObjectStateOptional(int object) { + return object >= objectStates.length ? null : objectStates[object]; } public ObjectState getObjectState(VirtualObjectNode object) { - assert objectStates.containsKey(object); - return objectStates.get(object); + ObjectState state = objectStates[object.getObjectId()]; + assert state != null; + return state; } public ObjectState getObjectStateOptional(VirtualObjectNode object) { - return objectStates.get(object); + int id = object.getObjectId(); + return id >= objectStates.length ? null : objectStates[id]; + } + + private ObjectState[] getObjectStateArrayForModification() { + if (arrayRefCount.refCount > 1) { + objectStates = objectStates.clone(); + arrayRefCount = new RefCount(); + } + return objectStates; + } + + private ObjectState getObjectStateForModification(int object) { + ObjectState[] array = getObjectStateArrayForModification(); + ObjectState objectState = array[object]; + if (objectState.copyOnWrite) { + array[object] = objectState = objectState.cloneState(); + } + return objectState; } - public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) { + public void setEntry(int object, int entryIndex, ValueNode value) { + if (objectStates[object].getEntry(entryIndex) != value) { + getObjectStateForModification(object).setEntry(entryIndex, value); + } + } + + public void escape(int object, ValueNode materialized) { + getObjectStateForModification(object).escape(materialized); + } + + public void addLock(int object, MonitorIdNode monitorId) { + getObjectStateForModification(object).addLock(monitorId); + } + + public MonitorIdNode removeLock(int object) { + return getObjectStateForModification(object).removeLock(); + } + + public void setEnsureVirtualized(int object, boolean ensureVirtualized) { + if (objectStates[object].getEnsureVirtualized() != ensureVirtualized) { + getObjectStateForModification(object).setEnsureVirtualized(ensureVirtualized); + } + } + + public void updateMaterializedValue(int object, ValueNode value) { + if (objectStates[object].getMaterializedValue() != value) { + getObjectStateForModification(object).updateMaterializedValue(value); + } + } + + public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) { PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); List<AllocatedObjectNode> objects = new ArrayList<>(2); List<ValueNode> values = new ArrayList<>(8); List<List<MonitorIdNode>> locks = new ArrayList<>(2); List<ValueNode> otherAllocations = new ArrayList<>(2); List<Boolean> ensureVirtual = new ArrayList<>(2); - materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations, state); + materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations); materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> { for (ValueNode otherAllocation : otherAllocations) { @@ -117,13 +182,14 @@ } private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values, - List<Boolean> ensureVirtual, List<ValueNode> otherAllocations, EscapeState state) { + List<Boolean> ensureVirtual, List<ValueNode> otherAllocations) { ObjectState obj = getObjectState(virtual); ValueNode[] entries = obj.getEntries(); ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks()); - obj.escape(representation, state); - PartialEscapeClosure.updateStatesForMaterialized(this, obj); + escape(virtual.getObjectId(), representation); + obj = getObjectState(virtual); + PartialEscapeClosure.updateStatesForMaterialized(this, virtual, obj.getMaterializedValue()); if (representation instanceof AllocatedObjectNode) { objects.add((AllocatedObjectNode) representation); locks.add(LockState.asList(obj.getLocks())); @@ -134,9 +200,11 @@ } for (int i = 0; i < entries.length; i++) { if (entries[i] instanceof VirtualObjectNode) { - ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]); + VirtualObjectNode entryVirtual = (VirtualObjectNode) entries[i]; + ObjectState entryObj = getObjectState(entryVirtual); if (entryObj.isVirtual()) { - materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, ensureVirtual, otherAllocations, state); + materializeWithCommit(fixed, entryVirtual, objects, locks, values, ensureVirtual, otherAllocations); + entryObj = getObjectState(entryVirtual); } values.set(pos + i, entryObj.getMaterializedValue()); } else { @@ -155,26 +223,46 @@ VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values); } - public void addObject(VirtualObjectNode virtual, ObjectState state) { - objectStates.put(virtual, state); + public void addObject(int virtual, ObjectState state) { + ensureSize(virtual)[virtual] = state; } - public Iterable<ObjectState> getStates() { - return objectStates.values(); + private ObjectState[] ensureSize(int objectId) { + if (objectStates.length <= objectId) { + objectStates = Arrays.copyOf(objectStates, Math.max(objectId * 2, 4)); + arrayRefCount.refCount--; + arrayRefCount = new RefCount(); + return objectStates; + } else { + return getObjectStateArrayForModification(); + } } - public Set<VirtualObjectNode> getVirtualObjects() { - return objectStates.keySet(); + public int getStateCount() { + return objectStates.length; } @Override public String toString() { - return super.toString() + ", Object States: " + objectStates; + return super.toString() + ", Object States: " + Arrays.toString(objectStates); } @Override public boolean equivalentTo(T other) { - return compareMaps(objectStates, other.objectStates); + int length = Math.max(objectStates.length, other.getStateCount()); + for (int i = 0; i < length; i++) { + ObjectState left = getObjectStateOptional(i); + ObjectState right = other.getObjectStateOptional(i); + if (left != right) { + if (left == null || right == null) { + return false; + } + if (!left.equals(right)) { + return false; + } + } + } + return true; } protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) { @@ -212,4 +300,42 @@ } } + public void resetObjectStates(int size) { + objectStates = new ObjectState[size]; + } + + public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states) { + for (int i = 1; i < states.length; i++) { + if (states[0].objectStates != states[i].objectStates) { + return false; + } + } + return true; + } + + public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states, int object) { + for (int i = 1; i < states.length; i++) { + if (states[0].objectStates[object] != states[i].objectStates[object]) { + return false; + } + } + return true; + } + + public void adoptAddObjectStates(PartialEscapeBlockState<?> other) { + if (objectStates != null) { + arrayRefCount.refCount--; + } + objectStates = other.objectStates; + arrayRefCount = other.arrayRefCount; + + if (arrayRefCount.refCount == 1) { + for (ObjectState state : objectStates) { + if (state != null) { + state.share(); + } + } + } + arrayRefCount.refCount++; + } }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Jul 29 11:59:18 2015 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.virtual.phases.ea; import java.util.*; +import java.util.function.*; import com.oracle.graal.debug.*; import jdk.internal.jvmci.meta.*; @@ -37,7 +38,6 @@ import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.schedule.*; @@ -56,12 +56,14 @@ private final NodeBitMap hasVirtualInputs; private final VirtualizerToolImpl tool; + public final ArrayList<VirtualObjectNode> virtualObjects = new ArrayList<>(); + private final class CollectVirtualObjectsClosure extends NodeClosure<ValueNode> { - private final Set<ObjectState> virtual; + private final Set<VirtualObjectNode> virtual; private final GraphEffectList effects; private final BlockT state; - private CollectVirtualObjectsClosure(Set<ObjectState> virtual, GraphEffectList effects, BlockT state) { + private CollectVirtualObjectsClosure(Set<VirtualObjectNode> virtual, GraphEffectList effects, BlockT state) { this.virtual = virtual; this.effects = effects; this.state = state; @@ -69,20 +71,17 @@ @Override public void apply(Node usage, ValueNode value) { - ObjectState valueObj = getObjectState(state, value); - if (valueObj != null) { - virtual.add(valueObj); - effects.replaceFirstInput(usage, value, valueObj.virtual); - } else if (value instanceof VirtualObjectNode) { - ObjectState virtualObj = null; - for (ObjectState obj : state.getStates()) { - if (value == obj.virtual) { - virtualObj = obj; - break; - } + if (value instanceof VirtualObjectNode) { + VirtualObjectNode object = (VirtualObjectNode) value; + if (object.getObjectId() != -1 && state.getObjectStateOptional(object) != null) { + virtual.add(object); } - if (virtualObj != null) { - virtual.add(virtualObj); + } else { + ValueNode alias = getAlias(value); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode object = (VirtualObjectNode) alias; + virtual.add(object); + effects.replaceFirstInput(usage, value, object); } } } @@ -196,17 +195,11 @@ } if (canonicalizedValue != node && canonicalizedValue != null) { if (canonicalizedValue.isAlive()) { - ObjectState obj = getObjectState(state, canonicalizedValue); - if (obj != null) { - if (obj.getState() == EscapeState.Virtual) { - addAndMarkAlias(obj.virtual, node); - effects.deleteNode(node); - } else { - effects.replaceAtUsages(node, obj.getMaterializedValue()); - addScalarAlias(node, obj.getMaterializedValue()); - } + ValueNode alias = getAliasAndResolve(state, canonicalizedValue); + if (alias instanceof VirtualObjectNode) { + addAndMarkAlias((VirtualObjectNode) alias, node); + effects.deleteNode(node); } else { - ValueNode alias = getScalarAlias(canonicalizedValue); effects.replaceAtUsages(node, alias); addScalarAlias(node, alias); } @@ -240,7 +233,7 @@ if (input.isAlive()) { ObjectState obj = getObjectState(state, (ValueNode) input); if (obj != null) { - if (obj.getState() == EscapeState.Virtual) { + if (obj.isVirtual()) { return false; } else { pos.initialize(node, obj.getMaterializedValue()); @@ -262,10 +255,12 @@ VirtualUtil.trace("processing nodewithstate: %s", node); for (Node input : node.inputs()) { if (input instanceof ValueNode) { - ObjectState obj = getObjectState(state, (ValueNode) input); - if (obj != null) { - VirtualUtil.trace("replacing input %s at %s: %s", input, node, obj); - replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED); + ValueNode alias = getAlias((ValueNode) input); + if (alias instanceof VirtualObjectNode) { + int id = ((VirtualObjectNode) alias).getObjectId(); + ensureMaterialized(state, id, insertBefore, effects, METRIC_MATERIALIZATIONS_UNHANDLED); + effects.replaceFirstInput(node, input, state.getObjectState(id).getMaterializedValue()); + VirtualUtil.trace("replacing input %s at %s", input, node); } } } @@ -287,11 +282,11 @@ private void processNodeWithState(NodeWithState nodeWithState, BlockT state, GraphEffectList effects) { for (FrameState fs : nodeWithState.states()) { FrameState frameState = getUniqueFramestate(nodeWithState, fs); - Set<ObjectState> virtual = new ArraySet<>(); + Set<VirtualObjectNode> virtual = new ArraySet<>(); frameState.applyToNonVirtual(new CollectVirtualObjectsClosure(virtual, effects, state)); collectLockedVirtualObjects(state, virtual); collectReferencedVirtualObjects(state, virtual); - addVirtualMappings(effects, frameState, virtual); + addVirtualMappings(frameState, virtual, state, effects); } } @@ -305,23 +300,27 @@ return frameState; } - private static void addVirtualMappings(GraphEffectList effects, FrameState frameState, Set<ObjectState> virtual) { - for (ObjectState obj : virtual) { - effects.addVirtualMapping(frameState, obj.createEscapeObjectState()); + private void addVirtualMappings(FrameState frameState, Set<VirtualObjectNode> virtual, BlockT state, GraphEffectList effects) { + for (VirtualObjectNode obj : virtual) { + effects.addVirtualMapping(frameState, state.getObjectState(obj).createEscapeObjectState(obj)); } } - private void collectReferencedVirtualObjects(final BlockT state, final Set<ObjectState> virtual) { - ArrayDeque<ObjectState> queue = new ArrayDeque<>(virtual); + private void collectReferencedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) { + ArrayDeque<VirtualObjectNode> queue = new ArrayDeque<>(virtual); while (!queue.isEmpty()) { - ObjectState obj = queue.removeLast(); - if (obj.isVirtual()) { - for (ValueNode entry : obj.getEntries()) { - if (entry instanceof VirtualObjectNode) { - ObjectState fieldObj = state.getObjectState((VirtualObjectNode) entry); - if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) { - virtual.add(fieldObj); - queue.addLast(fieldObj); + VirtualObjectNode object = queue.removeLast(); + int id = object.getObjectId(); + if (id != -1) { + ObjectState objState = state.getObjectStateOptional(id); + if (objState != null && objState.isVirtual()) { + for (ValueNode entry : objState.getEntries()) { + if (entry instanceof VirtualObjectNode) { + VirtualObjectNode entryVirtual = (VirtualObjectNode) entry; + if (!virtual.contains(entryVirtual)) { + virtual.add(entryVirtual); + queue.addLast(entryVirtual); + } } } } @@ -329,10 +328,11 @@ } } - private void collectLockedVirtualObjects(final BlockT state, Set<ObjectState> virtual) { - for (ObjectState obj : state.getStates()) { - if (obj.isVirtual() && obj.hasLocks()) { - virtual.add(obj); + private void collectLockedVirtualObjects(BlockT state, Set<VirtualObjectNode> virtual) { + for (int i = 0; i < state.getStateCount(); i++) { + ObjectState objState = state.getObjectStateOptional(i); + if (objState != null && objState.isVirtual() && objState.hasLocks()) { + virtual.add(virtualObjects.get(i)); } } } @@ -340,49 +340,41 @@ /** * @return true if materialization happened, false if not. */ - private boolean ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { - assert obj != null; - if (obj.getState() == EscapeState.Virtual) { + private boolean ensureMaterialized(PartialEscapeBlockState<?> state, int object, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { + if (state.getObjectState(object).isVirtual()) { metric.increment(); - state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects); - updateStatesForMaterialized(state, obj); - assert !obj.isVirtual(); + VirtualObjectNode virtual = virtualObjects.get(object); + state.materializeBefore(materializeBefore, virtual, effects); + updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue()); return true; } else { - assert obj.getState() == EscapeState.Materialized; return false; } } - public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, ObjectState obj) { + public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, VirtualObjectNode virtual, ValueNode materializedValue) { // update all existing states with the newly materialized object - for (ObjectState objState : state.objectStates.values()) { - if (objState.isVirtual()) { + for (int i = 0; i < state.getStateCount(); i++) { + ObjectState objState = state.getObjectStateOptional(i); + if (objState != null && objState.isVirtual()) { ValueNode[] entries = objState.getEntries(); - for (int i = 0; i < entries.length; i++) { - if (entries[i] == obj.virtual) { - objState.setEntry(i, obj.getMaterializedValue()); + for (int i2 = 0; i2 < entries.length; i2++) { + if (entries[i2] == virtual) { + state.setEntry(i, i2, materializedValue); } } } } } - private boolean replaceWithMaterialized(Node value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { - boolean materialized = ensureMaterialized(state, obj, materializeBefore, effects, metric); - effects.replaceFirstInput(usage, value, obj.getMaterializedValue()); - return materialized; - } - @Override protected void processInitialLoopState(Loop<Block> loop, BlockT initialState) { - super.processInitialLoopState(loop, initialState); - for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) { if (phi.valueAt(0) != null) { - ObjectState state = getObjectState(initialState, phi.valueAt(0)); - if (state != null && state.isVirtual()) { - addAndMarkAlias(state.virtual, phi); + ValueNode alias = getAliasAndResolve(initialState, phi.valueAt(0)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + addAndMarkAlias(virtual, phi); } } } @@ -391,49 +383,55 @@ @Override protected void processLoopExit(LoopExitNode exitNode, BlockT initialState, BlockT exitState, GraphEffectList effects) { if (exitNode.graph().hasValueProxies()) { - Map<VirtualObjectNode, ProxyNode> proxies = Node.newMap(); + Map<Integer, ProxyNode> proxies = new IdentityHashMap<>(); for (ProxyNode proxy : exitNode.proxies()) { - ObjectState obj = getObjectState(exitState, proxy.value()); - if (obj != null) { - proxies.put(obj.virtual, proxy); + ValueNode alias = getAlias(proxy.value()); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + proxies.put(virtual.getObjectId(), proxy); } } - for (ObjectState obj : exitState.getStates()) { - ObjectState initialObj = initialState.getObjectStateOptional(obj.virtual); - if (obj.isVirtual()) { - processVirtualAtLoopExit(exitNode, effects, obj, initialObj); - } else { - processMaterializedAtLoopExit(exitNode, effects, proxies, obj, initialObj); + for (int i = 0; i < exitState.getStateCount(); i++) { + ObjectState exitObjState = exitState.getObjectStateOptional(i); + if (exitObjState != null) { + ObjectState initialObjState = initialState.getObjectStateOptional(i); + + if (exitObjState.isVirtual()) { + processVirtualAtLoopExit(exitNode, effects, i, exitObjState, initialObjState, exitState); + } else { + processMaterializedAtLoopExit(exitNode, effects, proxies, i, exitObjState, initialObjState, exitState); + } } } } } - private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map<VirtualObjectNode, ProxyNode> proxies, ObjectState obj, ObjectState initialObj) { - if (initialObj == null || initialObj.isVirtual()) { - ProxyNode proxy = proxies.get(obj.virtual); + private static void processMaterializedAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, Map<Integer, ProxyNode> proxies, int object, ObjectState exitObjState, + ObjectState initialObjState, PartialEscapeBlockState<?> exitState) { + if (initialObjState == null || initialObjState.isVirtual()) { + ProxyNode proxy = proxies.get(object); if (proxy == null) { - proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode); + proxy = new ValueProxyNode(exitObjState.getMaterializedValue(), exitNode); effects.addFloatingNode(proxy, "proxy"); } else { - effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); + effects.replaceFirstInput(proxy, proxy.value(), exitObjState.getMaterializedValue()); // nothing to do - will be handled in processNode } - obj.updateMaterializedValue(proxy); + exitState.updateMaterializedValue(object, proxy); } else { - if (initialObj.getMaterializedValue() == obj.getMaterializedValue()) { - Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObj.getMaterializedValue(), obj.getMaterializedValue(), exitNode); + if (initialObjState.getMaterializedValue() != exitObjState.getMaterializedValue()) { + Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObjState.getMaterializedValue(), exitObjState.getMaterializedValue(), exitNode); } } } - private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, ObjectState obj, ObjectState initialObj) { - for (int i = 0; i < obj.getEntries().length; i++) { - ValueNode value = obj.getEntry(i); + private static void processVirtualAtLoopExit(LoopExitNode exitNode, GraphEffectList effects, int object, ObjectState exitObjState, ObjectState initialObjState, PartialEscapeBlockState<?> exitState) { + for (int i = 0; i < exitObjState.getEntries().length; i++) { + ValueNode value = exitState.getObjectState(object).getEntry(i); if (!(value instanceof VirtualObjectNode || value.isConstant())) { - if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { + if (exitNode.loopBegin().isPhiAtMerge(value) || initialObjState == null || !initialObjState.isVirtual() || initialObjState.getEntry(i) != value) { ProxyNode proxy = new ValueProxyNode(value, exitNode); - obj.setEntry(i, proxy); + exitState.setEntry(object, i, proxy); effects.addFloatingNode(proxy, "virtualProxy"); } } @@ -525,56 +523,72 @@ * reached. This method needs to be careful to place the effects of the merging operation * into the correct blocks. * - * @param states the predecessor block states of the merge + * @param statesList the predecessor block states of the merge */ @Override - protected void merge(List<BlockT> states) { - super.merge(states); + protected void merge(List<BlockT> statesList) { + super.merge(statesList); + + PartialEscapeBlockState<?>[] states = new PartialEscapeBlockState<?>[statesList.size()]; + for (int i = 0; i < statesList.size(); i++) { + states[i] = statesList.get(i); + } // calculate the set of virtual objects that exist in all predecessors - Set<VirtualObjectNode> virtualObjTemp = intersectVirtualObjects(states); + int[] virtualObjTemp = intersectVirtualObjects(states); - ObjectState[] objStates = new ObjectState[states.size()]; boolean materialized; do { materialized = false; - for (VirtualObjectNode object : virtualObjTemp) { - for (int i = 0; i < objStates.length; i++) { - objStates[i] = states.get(i).getObjectState(object); - } + + if (PartialEscapeBlockState.identicalObjectStates(states)) { + newState.adoptAddObjectStates(states[0]); + } else { - // determine if all inputs are virtual or the same materialized value - int virtual = 0; - ObjectState startObj = objStates[0]; - boolean locksMatch = true; - ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); - for (ObjectState obj : objStates) { - if (obj.isVirtual()) { - virtual++; - uniqueMaterializedValue = null; - locksMatch &= obj.locksEqual(startObj); - } else if (obj.getMaterializedValue() != uniqueMaterializedValue) { - uniqueMaterializedValue = null; + for (int object : virtualObjTemp) { + + if (PartialEscapeBlockState.identicalObjectStates(states, object)) { + newState.addObject(object, states[0].getObjectState(object).share()); + continue; } - } - if (virtual == objStates.length && locksMatch) { - materialized |= mergeObjectStates(object, objStates, states); - } else { - if (uniqueMaterializedValue != null) { - newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null, false)); + // determine if all inputs are virtual or the same materialized value + int virtualCount = 0; + ObjectState startObj = states[0].getObjectState(object); + boolean locksMatch = true; + boolean ensureVirtual = true; + ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); + for (int i = 0; i < states.length; i++) { + ObjectState obj = states[i].getObjectState(object); + ensureVirtual &= obj.getEnsureVirtualized(); + if (obj.isVirtual()) { + virtualCount++; + uniqueMaterializedValue = null; + locksMatch &= obj.locksEqual(startObj); + } else if (obj.getMaterializedValue() != uniqueMaterializedValue) { + uniqueMaterializedValue = null; + } + } + + if (virtualCount == states.length && locksMatch) { + materialized |= mergeObjectStates(object, null, states); } else { - PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); - mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - if (obj.isVirtual()) { - Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + if (uniqueMaterializedValue != null) { + newState.addObject(object, new ObjectState(uniqueMaterializedValue, null, ensureVirtual)); + } else { + PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); + mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); + for (int i = 0; i < states.length; i++) { + ObjectState obj = states[i].getObjectState(object); + if (obj.isVirtual()) { + Block predecessor = getPredecessor(i); + materialized |= ensureMaterialized(states[i], object, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + obj = states[i].getObjectState(object); + } + setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); } - setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); + newState.addObject(object, new ObjectState(materializedValuePhi, null, false)); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false)); } } } @@ -585,19 +599,41 @@ } } if (materialized) { - newState.objectStates.clear(); + newState.resetObjectStates(virtualObjects.size()); mergeEffects.clear(); afterMergeEffects.clear(); } } while (materialized); } - private Set<VirtualObjectNode> intersectVirtualObjects(List<BlockT> states) { - Set<VirtualObjectNode> virtualObjTemp = Node.newSet(states.get(0).getVirtualObjects()); - for (int i = 1; i < states.size(); i++) { - virtualObjTemp.retainAll(states.get(i).getVirtualObjects()); + private int[] intersectVirtualObjects(PartialEscapeBlockState<?>[] states) { + int length = states[0].getStateCount(); + for (int i = 1; i < states.length; i++) { + length = Math.min(length, states[i].getStateCount()); } - return virtualObjTemp; + boolean[] result = new boolean[length]; + Arrays.fill(result, true); + int count = length; + for (int i = 0; i < states.length; i++) { + PartialEscapeBlockState<?> state = states[i]; + for (int i2 = 0; i2 < length; i2++) { + if (result[i2]) { + if (state.getObjectStateOptional(i2) == null) { + result[i2] = false; + count--; + } + } + } + } + int[] resultInts = new int[count]; + int index = 0; + for (int i = 0; i < length; i++) { + if (result[i]) { + resultInts[index++] = i; + } + } + assert index == count; + return resultInts; } /** @@ -608,28 +644,30 @@ * can be incompatible if they contain {@code long} or {@code double} values occupying two * {@code int} slots in such a way that that their values cannot be merged using PhiNodes. * - * @param object the virtual object that should be associated with the merged object state - * @param objStates the incoming object states (all of which need to be virtual) - * @param blockStates the predecessor block states of the merge + * @param states the predecessor block states of the merge * @return true if materialization happened during the merge, false otherwise */ - private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List<BlockT> blockStates) { + private boolean mergeObjectStates(int resultObject, int[] sourceObjects, PartialEscapeBlockState<?>[] states) { boolean compatible = true; boolean ensureVirtual = true; - ValueNode[] values = objStates[0].getEntries().clone(); + IntFunction<Integer> getObject = index -> sourceObjects == null ? resultObject : sourceObjects[index]; + + VirtualObjectNode virtual = virtualObjects.get(resultObject); + int entryCount = virtual.entryCount(); // determine all entries that have a two-slot value Kind[] twoSlotKinds = null; - outer: for (int i = 0; i < objStates.length; i++) { - ValueNode[] entries = objStates[i].getEntries(); + outer: for (int i = 0; i < states.length; i++) { + ObjectState objectState = states[i].getObjectState(getObject.apply(i)); + ValueNode[] entries = objectState.getEntries(); int valueIndex = 0; - ensureVirtual &= objStates[i].getEnsureVirtualized(); - while (valueIndex < values.length) { + ensureVirtual &= objectState.getEnsureVirtualized(); + while (valueIndex < entryCount) { Kind otherKind = entries[valueIndex].getKind(); - Kind entryKind = object.entryKind(valueIndex); + Kind entryKind = virtual.entryKind(valueIndex); if (entryKind == Kind.Int && otherKind.needsTwoSlots()) { if (twoSlotKinds == null) { - twoSlotKinds = new Kind[values.length]; + twoSlotKinds = new Kind[entryCount]; } if (twoSlotKinds[valueIndex] != null && twoSlotKinds[valueIndex] != otherKind) { compatible = false; @@ -647,18 +685,20 @@ } if (compatible && twoSlotKinds != null) { // if there are two-slot values then make sure the incoming states can be merged - outer: for (int valueIndex = 0; valueIndex < values.length; valueIndex++) { + outer: for (int valueIndex = 0; valueIndex < entryCount; valueIndex++) { if (twoSlotKinds[valueIndex] != null) { - assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int; - for (int i = 0; i < objStates.length; i++) { - ValueNode value = objStates[i].getEntry(valueIndex); + assert valueIndex < virtual.entryCount() - 1 && virtual.entryKind(valueIndex) == Kind.Int && virtual.entryKind(valueIndex + 1) == Kind.Int; + for (int i = 0; i < states.length; i++) { + int object = getObject.apply(i); + ObjectState objectState = states[i].getObjectState(object); + ValueNode value = objectState.getEntry(valueIndex); Kind valueKind = value.getKind(); if (valueKind != twoSlotKinds[valueIndex]) { - ValueNode nextValue = objStates[i].getEntry(valueIndex + 1); + ValueNode nextValue = objectState.getEntry(valueIndex + 1); if (value.isConstant() && value.asConstant().equals(JavaConstant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(JavaConstant.INT_0)) { // rewrite to a zero constant of the larger kind - objStates[i].setEntry(valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph())); - objStates[i].setEntry(valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph())); + states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph())); + states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph())); } else { compatible = false; break outer; @@ -671,12 +711,13 @@ if (compatible) { // virtual objects are compatible: create phis for all entries that need them - PhiNode[] phis = getValuePhis(object, object.entryCount()); + ValueNode[] values = states[0].getObjectState(getObject.apply(0)).getEntries().clone(); + PhiNode[] phis = getValuePhis(virtual, virtual.entryCount()); int valueIndex = 0; while (valueIndex < values.length) { - for (int i = 1; i < objStates.length; i++) { + for (int i = 1; i < states.length; i++) { if (phis[valueIndex] == null) { - ValueNode field = objStates[i].getEntry(valueIndex); + ValueNode field = states[i].getObjectState(getObject.apply(i)).getEntry(valueIndex); if (values[valueIndex] != field) { phis[valueIndex] = createValuePhi(values[valueIndex].stamp().unrestricted()); } @@ -699,26 +740,31 @@ PhiNode phi = phis[i]; if (phi != null) { mergeEffects.addFloatingNode(phi, "virtualMergePhi"); - if (object.entryKind(i) == Kind.Object) { - materialized |= mergeObjectEntry(objStates, blockStates, phi, i); + if (virtual.entryKind(i) == Kind.Object) { + materialized |= mergeObjectEntry(getObject, states, phi, i); } else { - mergePrimitiveEntry(objStates, phi, i); + for (int i2 = 0; i2 < states.length; i2++) { + ObjectState state = states[i2].getObjectState(getObject.apply(i2)); + if (!state.isVirtual()) { + break; + } + setPhiInput(phi, i2, state.getEntry(i)); + } } values[i] = phi; } } - newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks(), ensureVirtual)); + newState.addObject(resultObject, new ObjectState(values, states[0].getObjectState(getObject.apply(0)).getLocks(), ensureVirtual)); return materialized; } else { // not compatible: materialize in all predecessors - PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object)); - for (int i = 0; i < blockStates.size(); i++) { - ObjectState obj = objStates[i]; + PhiNode materializedValuePhi = getPhi(resultObject, StampFactory.forKind(Kind.Object)); + for (int i = 0; i < states.length; i++) { Block predecessor = getPredecessor(i); - ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); - setPhiInput(materializedValuePhi, i, obj.getMaterializedValue()); + ensureMaterialized(states[i], getObject.apply(i), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + setPhiInput(materializedValuePhi, i, states[i].getObjectState(getObject.apply(i)).getMaterializedValue()); } - newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false)); + newState.addObject(resultObject, new ObjectState(materializedValuePhi, null, ensureVirtual)); return true; } } @@ -729,19 +775,22 @@ * * @return true if materialization happened during the merge, false otherwise */ - private boolean mergeObjectEntry(ObjectState[] objStates, List<BlockT> blockStates, PhiNode phi, int entryIndex) { + private boolean mergeObjectEntry(IntFunction<Integer> objectIdFunc, PartialEscapeBlockState<?>[] states, PhiNode phi, int entryIndex) { boolean materialized = false; - for (int i = 0; i < objStates.length; i++) { - if (!objStates[i].isVirtual()) { + for (int i = 0; i < states.length; i++) { + int object = objectIdFunc.apply(i); + ObjectState objectState = states[i].getObjectState(object); + if (!objectState.isVirtual()) { break; } - ValueNode entry = objStates[i].getEntry(entryIndex); + ValueNode entry = objectState.getEntry(entryIndex); if (entry instanceof VirtualObjectNode) { - ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entry); + VirtualObjectNode entryVirtual = (VirtualObjectNode) entry; Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); - if (objStates[i].isVirtual()) { - objStates[i].setEntry(entryIndex, entry = obj.getMaterializedValue()); + materialized |= ensureMaterialized(states[i], entryVirtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + objectState = states[i].getObjectState(object); + if (objectState.isVirtual()) { + states[i].setEntry(object, entryIndex, entry = states[i].getObjectState(entryVirtual.getObjectId()).getMaterializedValue()); } } setPhiInput(phi, i, entry); @@ -750,20 +799,6 @@ } /** - * Fill the inputs of the PhiNode corresponding to one primitive entry in the virtual - * object. - */ - private void mergePrimitiveEntry(ObjectState[] objStates, PhiNode phi, int entryIndex) { - for (int i = 0; i < objStates.length; i++) { - ObjectState state = objStates[i]; - if (!state.isVirtual()) { - break; - } - setPhiInput(phi, i, state.getEntry(entryIndex)); - } - } - - /** * Examine a PhiNode and try to replace it with merging of virtual objects if all its inputs * refer to virtual object states. In order for the merging to happen, all incoming object * states need to be compatible and without object identity (meaning that their object @@ -775,40 +810,46 @@ * and therefore also exist in the merged state * @return true if materialization happened during the merge, false otherwise */ - private boolean processPhi(ValuePhiNode phi, List<BlockT> states, Set<VirtualObjectNode> mergedVirtualObjects) { + private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState<?>[] states, int[] mergedVirtualObjects) { aliases.set(phi, null); // determine how many inputs are virtual and if they're all the same virtual object int virtualInputs = 0; - ObjectState[] objStates = new ObjectState[states.size()]; boolean uniqueVirtualObject = true; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i] = getObjectState(states.get(i), getPhiValueAt(phi, i)); - if (obj != null) { - if (obj.isVirtual()) { - if (objStates[0] == null || objStates[0].virtual != obj.virtual) { + VirtualObjectNode[] virtualObjs = new VirtualObjectNode[states.length]; + for (int i = 0; i < states.length; i++) { + ValueNode alias = getAlias(getPhiValueAt(phi, i)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode virtual = (VirtualObjectNode) alias; + virtualObjs[i] = virtual; + if (states[i].getObjectState(virtual).isVirtual()) { + if (virtualObjs[0] != alias) { uniqueVirtualObject = false; } virtualInputs++; } } } - if (virtualInputs == objStates.length) { + if (virtualInputs == states.length) { if (uniqueVirtualObject) { // all inputs refer to the same object: just make the phi node an alias - addAndMarkAlias(objStates[0].virtual, phi); + addAndMarkAlias(virtualObjs[0], phi); mergeEffects.deleteNode(phi); return false; } else { // all inputs are virtual: check if they're compatible and without identity boolean compatible = true; boolean hasIdentity = false; - ObjectState firstObj = objStates[0]; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - hasIdentity |= obj.virtual.hasIdentity(); - boolean identitySurvives = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual); - if (identitySurvives || !firstObj.virtual.type().equals(obj.virtual.type()) || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) { + VirtualObjectNode firstVirtual = virtualObjs[0]; + for (int i = 0; i < states.length; i++) { + VirtualObjectNode virtual = virtualObjs[i]; + hasIdentity |= virtual.hasIdentity(); + boolean identitySurvives = virtual.hasIdentity() && Arrays.asList(mergedVirtualObjects).contains(virtual.getObjectId()); + if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { + compatible = false; + break; + } + if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) { compatible = false; break; } @@ -816,22 +857,34 @@ if (compatible && hasIdentity) { // we still need to check whether this value is referenced by any other phi outer: for (PhiNode otherPhi : getPhis().filter(otherPhi -> otherPhi != phi)) { - for (int i = 0; i < objStates.length; i++) { - ObjectState otherPhiValueState = getObjectState(states.get(i), getPhiValueAt(otherPhi, i)); - if (Arrays.asList(objStates).contains(otherPhiValueState)) { - compatible = false; - break outer; + for (int i = 0; i < states.length; i++) { + ValueNode alias = getAliasAndResolve(states[i], getPhiValueAt(otherPhi, i)); + if (alias instanceof VirtualObjectNode) { + VirtualObjectNode phiValueVirtual = (VirtualObjectNode) alias; + if (Arrays.asList(virtualObjs).contains(phiValueVirtual)) { + compatible = false; + break outer; + } } } } } if (compatible) { - VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), getPhiValueAt(phi, 0)).virtual); + VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]); mergeEffects.addFloatingNode(virtual, "valueObjectNode"); mergeEffects.deleteNode(phi); + if (virtual.getObjectId() == -1) { + int id = virtualObjects.size(); + virtualObjects.add(virtual); + virtual.setObjectId(id); + } - boolean materialized = mergeObjectStates(virtual, objStates, states); + int[] virtualObjectIds = new int[states.length]; + for (int i = 0; i < states.length; i++) { + virtualObjectIds[i] = virtualObjs[i].getObjectId(); + } + boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states); addAndMarkAlias(virtual, virtual); addAndMarkAlias(virtual, phi); return materialized; @@ -841,12 +894,12 @@ // otherwise: materialize all phi inputs boolean materialized = false; - for (int i = 0; i < objStates.length; i++) { - ObjectState obj = objStates[i]; - if (obj != null) { + for (int i = 0; i < states.length; i++) { + VirtualObjectNode virtual = virtualObjs[i]; + if (virtual != null) { Block predecessor = getPredecessor(i); - materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); - setPhiInput(phi, i, obj.getMaterializedValue()); + materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); + setPhiInput(phi, i, getAliasAndResolve(states[i], virtual)); } } return materialized; @@ -868,6 +921,29 @@ } } + public ValueNode getAlias(ValueNode value) { + if (value != null && !(value instanceof VirtualObjectNode)) { + if (value.isAlive() && !aliases.isNew(value)) { + ValueNode result = aliases.get(value); + if (result != null) { + return result; + } + } + } + return value; + } + + public ValueNode getAliasAndResolve(PartialEscapeBlockState<?> state, ValueNode value) { + ValueNode result = getAlias(value); + if (result instanceof VirtualObjectNode) { + int id = ((VirtualObjectNode) result).getObjectId(); + if (id != -1 && !state.getObjectState(id).isVirtual()) { + result = state.getObjectState(id).getMaterializedValue(); + } + } + return result; + } + void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) { if (node.isAlive()) { aliases.set(node, virtual);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; @@ -83,6 +84,9 @@ @Override protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) { + for (VirtualObjectNode virtual : cfg.graph.getNodes(VirtualObjectNode.TYPE)) { + virtual.resetObjectId(); + } assert schedule != null; if (readElimination) { return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection());
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Wed Jul 29 11:59:18 2015 +0200 @@ -27,8 +27,6 @@ import java.util.*; import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.debug.*; - import com.oracle.graal.debug.*; import jdk.internal.jvmci.meta.*; @@ -109,6 +107,7 @@ } if (!success) { TTY.println(); + Debug.dump(graph, "assertNonReachable"); } return success; }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Tue Jul 28 17:35:49 2015 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Wed Jul 29 11:59:18 2015 +0200 @@ -33,8 +33,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; -import com.oracle.graal.nodes.spi.Virtualizable.State; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; @@ -78,33 +76,35 @@ } @Override - public State getObjectState(ValueNode value) { - return closure.getObjectState(state, value); + public ValueNode getAlias(ValueNode value) { + return closure.getAliasAndResolve(state, value); + } + + public ValueNode getEntry(VirtualObjectNode virtualObject, int index) { + return state.getObjectState(virtualObject).getEntry(index); } @Override - public void setVirtualEntry(State objectState, int index, ValueNode value, boolean unsafe) { - ObjectState obj = (ObjectState) objectState; - assert obj != null && obj.isVirtual() : "not virtual: " + obj; + public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) { + ObjectState obj = state.getObjectState(virtual); + assert obj.isVirtual() : "not virtual: " + obj; ValueNode newValue; if (value == null) { newValue = null; } else { - ObjectState valueState = closure.getObjectState(state, value); - if (valueState == null) { - newValue = getReplacedValue(value); - assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); - } else { - if (valueState.getState() != EscapeState.Virtual) { - newValue = valueState.getMaterializedValue(); - assert newValue.getKind() == Kind.Object; - } else { - newValue = valueState.getVirtualObject(); - } - assert obj.getEntry(index) == null || isObjectEntry(obj.getEntry(index)); - } + newValue = closure.getAliasAndResolve(state, value); + assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getKind() == newValue.getKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); } - obj.setEntry(index, newValue); + state.setEntry(virtual.getObjectId(), index, newValue); + } + + public void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized) { + int id = virtualObject.getObjectId(); + state.setEnsureVirtualized(id, ensureVirtualized); + } + + public boolean getEnsureVirtualized(VirtualObjectNode virtualObject) { + return state.getObjectState(virtualObject).getEnsureVirtualized(); } private static boolean isObjectEntry(ValueNode value) { @@ -112,11 +112,6 @@ } @Override - public ValueNode getReplacedValue(ValueNode original) { - return closure.getScalarAlias(original); - } - - @Override public void replaceWithVirtual(VirtualObjectNode virtual) { closure.addAndMarkAlias(virtual, current); effects.deleteNode(current); @@ -157,16 +152,16 @@ effects.addFloatingNode(virtualObject, "newVirtualObject"); } for (int i = 0; i < entryState.length; i++) { - if (!(entryState[i] instanceof VirtualObjectNode)) { - ObjectState v = closure.getObjectState(state, entryState[i]); - if (v != null) { - entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue(); - } else { - entryState[i] = closure.getScalarAlias(entryState[i]); - } - } + ValueNode entry = entryState[i]; + entryState[i] = entry instanceof VirtualObjectNode ? entry : closure.getAliasAndResolve(state, entry); } - state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks, ensureVirtualized)); + int id = virtualObject.getObjectId(); + if (id == -1) { + id = closure.virtualObjects.size(); + closure.virtualObjects.add(virtualObject); + virtualObject.setObjectId(id); + } + state.addObject(id, new ObjectState(entryState, locks, ensureVirtualized)); closure.addAndMarkAlias(virtualObject, virtualObject); PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment(); } @@ -178,18 +173,23 @@ @Override public void replaceWith(ValueNode node) { - State resultState = getObjectState(node); - if (resultState == null) { - replaceWithValue(node); + if (node instanceof VirtualObjectNode) { + replaceWithVirtual((VirtualObjectNode) node); } else { - if (resultState.getState() == EscapeState.Virtual) { - replaceWithVirtual(resultState.getVirtualObject()); - } else { - replaceWithValue(resultState.getMaterializedValue()); - } + replaceWithValue(node); } } + public void addLock(VirtualObjectNode virtualObject, MonitorIdNode monitorId) { + int id = virtualObject.getObjectId(); + state.addLock(id, monitorId); + } + + public MonitorIdNode removeLock(VirtualObjectNode virtualObject) { + int id = virtualObject.getObjectId(); + return state.removeLock(id); + } + public MetaAccessProvider getMetaAccess() { return metaAccess; }
--- a/mx.graal/mx_graal.py Tue Jul 28 17:35:49 2015 -0700 +++ b/mx.graal/mx_graal.py Wed Jul 29 11:59:18 2015 +0200 @@ -281,6 +281,7 @@ graal_unit_test_runs = [ UnitTestRun('UnitTests', []), UnitTestRun('UnitTestsNonSSA', ['-G:-SSA_LIR']), + UnitTestRun('UnitTestsTraceRA', ['-G:+TraceRA']), ] _registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if platform.processor() == 'sparc' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14' @@ -294,6 +295,7 @@ BootstrapTest('BootstrapWithExceptionEdges', 'fastdebug', ['-esa', '-G:+StressInvokeWithExceptionNode']), BootstrapTest('BootstrapWithRegisterPressure', 'product', ['-esa', '-G:RegisterPressure=' + _registers]), BootstrapTest('BootstrapNonSSAWithRegisterPressure', 'product', ['-esa', '-G:-SSA_LIR', '-G:RegisterPressure=' + _registers]), + BootstrapTest('BootstrapTraceRAWithRegisterPressure', 'product', ['-esa', '-G:+TraceRA', '-G:RegisterPressure=' + _registers]), BootstrapTest('BootstrapWithImmutableCode', 'product', ['-esa', '-G:+ImmutableCode', '-G:+VerifyPhases']), ]
--- a/mx.graal/suite.py Tue Jul 28 17:35:49 2015 -0700 +++ b/mx.graal/suite.py Wed Jul 29 11:59:18 2015 +0200 @@ -6,7 +6,7 @@ "suites": [ { "name" : "jvmci", - "version" : "8217ef77a80a64b8b773ba1a91363dbeb3d782e6", + "version" : "528eeeca785ef0ed43138966bc0a301707fbf5d7", "urls" : [ {"url" : "https://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"}, {"url" : "http://lafo.ssw.uni-linz.ac.at/nexus/content/repositories/snapshots", "kind" : "binary"}, @@ -283,7 +283,6 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ - "com.oracle.graal.debug", "com.oracle.graal.nodeinfo", "com.oracle.graal.compiler.common", "com.oracle.graal.api.collections", @@ -381,7 +380,6 @@ "sourceDirs" : ["src"], "dependencies" : [ "com.oracle.graal.compiler.common", - "com.oracle.graal.debug", "com.oracle.graal.asm", ], "annotationProcessors" : ["jvmci:JVMCI_OPTIONS_PROCESSOR"], @@ -738,7 +736,7 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ - "jvmci:JVMCI_API", + "com.oracle.graal.debug", ], "annotationProcessors" : ["jvmci:JVMCI_OPTIONS_PROCESSOR"], "checkstyle" : "com.oracle.graal.graph",