# HG changeset patch # User Thomas Wuerthinger # Date 1309964558 -7200 # Node ID adbb7bca84b7ccece6856baa9df09445182f54bc # Parent 132aa6f2bbc01dde2646bccbce24fb5c87f6e84e# Parent ce7e5b3798f761bd4e609ef9e43c2b4e2bf6c089 Merge. diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Wed Jul 06 17:02:38 2011 +0200 @@ -26,6 +26,7 @@ import static java.lang.reflect.Modifier.*; import java.util.*; +import java.util.Map.Entry; import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.alloc.Interval.*; @@ -1837,117 +1838,162 @@ } } - CiValue toCiValue(int opId, Value value) { - if (value instanceof VirtualObject) { - return toCiVirtualObject(opId, (VirtualObject) value); - } else if (value != null && value.operand() != CiValue.IllegalValue) { - CiValue operand = value.operand(); - Constant con = null; - if (value instanceof Constant) { - con = (Constant) value; - } + private class DebugFrameBuilder { + + private final FrameState topState; + private final int opId; + private final BitMap frameRefMap; - assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)"; + private HashMap virtualObjects; + + public DebugFrameBuilder(FrameState topState, int opId, BitMap frameRefMap) { + this.topState = topState; + this.opId = opId; + this.frameRefMap = frameRefMap; + } - if (operand.isVariable()) { - OperandMode mode = OperandMode.Input; - LIRBlock block = blockForId(opId); - if (block.numberOfSux() == 1 && opId == block.lastLirInstructionId()) { - // generating debug information for the last instruction of a block. - // if this instruction 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 = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); - if (instr instanceof LIRBranch) { - if (block.liveOut.get(operandNumber(operand))) { - opId = block.suxAt(0).firstLirInstructionId(); - mode = OperandMode.Output; - } - } + private CiValue toCiValue(Value value) { + if (value instanceof VirtualObject) { + if (virtualObjects == null) { + virtualObjects = new HashMap(); + } + VirtualObject obj = (VirtualObject) value; + CiVirtualObject ciObj = virtualObjects.get(value); + if (ciObj == null) { + ciObj = CiVirtualObject.get(obj.type(), null, value.id()); + virtualObjects.put(obj, ciObj); + } + return ciObj; + } else if (value != null && value.operand() != CiValue.IllegalValue) { + CiValue operand = value.operand(); + Constant con = null; + if (value instanceof Constant) { + con = (Constant) value; } - // Get current location of operand - // The operand must be live because debug information is considered when building the intervals - // if the interval is not live, colorLirOperand will cause an assert on failure - operand = colorLirOperand((CiVariable) operand, opId, mode); - assert !hasCall(opId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls"; - return operand; - } else if (operand.isRegister()) { - assert false : "must not reach here"; - return operand; + assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)"; + + int tempOpId = this.opId; + if (operand.isVariable()) { + OperandMode mode = OperandMode.Input; + LIRBlock block = blockForId(tempOpId); + if (block.numberOfSux() == 1 && tempOpId == block.lastLirInstructionId()) { + // generating debug information for the last instruction of a block. + // if this instruction 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 = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); + if (instr instanceof LIRBranch) { + if (block.liveOut.get(operandNumber(operand))) { + tempOpId = block.suxAt(0).firstLirInstructionId(); + mode = OperandMode.Output; + } + } + } + + // Get current location of operand + // The operand must be live because debug information is considered when building the intervals + // if the interval is not live, colorLirOperand will cause an assert on failure + operand = colorLirOperand((CiVariable) operand, tempOpId, mode); + assert !hasCall(tempOpId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls"; + return operand; + } else if (operand.isRegister()) { + assert false : "must not reach here"; + return operand; + } else { + assert value instanceof Constant; + assert operand.isConstant() : "operand must be constant"; + return operand; + } } else { - assert value instanceof Constant; - assert operand.isConstant() : "operand must be constant"; - return operand; + // return a dummy value because real value not needed + return CiValue.IllegalValue; } - } else { - // return a dummy value because real value not needed - return CiValue.IllegalValue; } - } - private CiVirtualObject toCiVirtualObject(int opId, VirtualObject obj) { - RiType type = obj.type(); - EscapeField[] escapeFields = obj.fields(); - CiValue[] values = new CiValue[escapeFields.length]; - int valuesFilled = 0; + private CiFrame computeFrameForState(FrameState state) { + CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; + int valueIndex = 0; + + for (int i = 0; i < state.valuesSize(); i++) { + values[valueIndex++] = toCiValue(state.valueAt(i)); + } - VirtualObject current = obj; - do { - boolean found = false; - for (int i = 0; i < escapeFields.length; i++) { - if (escapeFields[i].representation() == current.field().representation()) { - if (values[i] == null) { - values[i] = toCiValue(opId, current.input()); - valuesFilled++; + for (int i = 0; i < state.locksSize(); i++) { + if (compilation.runtime.sizeOfBasicObjectLock() != 0) { + CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i); + values[valueIndex++] = monitorAddress; + CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i); + frameRefMap.set(objectAddress.index()); + } else { + Value lock = state.lockAt(i); + if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) { + // lock on class for synchronized static method + values[valueIndex++] = lock.asConstant(); + } else { + values[valueIndex++] = toCiValue(lock); } - found = true; - break; } } - assert found : type + "." + current.field() + " not found"; - current = current.object(); - } while (current != null && valuesFilled < values.length); - - for (int i = 0; i < escapeFields.length; i++) { - assert values[i] != null : type + "." + escapeFields[i]; - } - - return CiVirtualObject.get(type, values, obj.id()); - } - - CiFrame computeFrameForState(FrameState state, int opId, BitMap frameRefMap) { - CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; - int valueIndex = 0; - - for (int i = 0; i < state.valuesSize(); i++) { - values[valueIndex++] = toCiValue(opId, state.valueAt(i)); + CiFrame caller = null; + if (state.outerFrameState() != null) { + caller = computeFrameForState(state.outerFrameState()); + } + return new CiFrame(caller, state.method, state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize()); } - for (int i = 0; i < state.locksSize(); i++) { - if (compilation.runtime.sizeOfBasicObjectLock() != 0) { - CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i); - values[valueIndex++] = monitorAddress; - assert frameRefMap != null; - CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i); -// LIRDebugInfo.setBit(frameRefMap, objectAddress.index()); - frameRefMap.set(objectAddress.index()); - } else { - Value lock = state.lockAt(i); - if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) { - // lock on class for synchronized static method - values[valueIndex++] = lock.asConstant(); - } else { - values[valueIndex++] = toCiValue(opId, lock); - } + public CiFrame build() { + CiFrame frame = computeFrameForState(topState); + + if (virtualObjects != null) { + // collect all VirtualObjectField instances: + HashMap objectStates = new HashMap(); + FrameState current = topState; + do { + for (Node n : current.inputs().variablePart()) { + VirtualObjectField field = (VirtualObjectField) n; + // null states occur for objects with 0 fields + if (field != null && !objectStates.containsKey(field.object())) { + objectStates.put(field.object(), field); + } + } + current = current.outerFrameState(); + } while (current != null); + // fill in the CiVirtualObject values: + // during this process new CiVirtualObjects might be discovered, so repeat until no more changes occur. + boolean changed; + do { + changed = false; + HashMap virtualObjectsCopy = new HashMap(virtualObjects); + for (Entry entry : virtualObjectsCopy.entrySet()) { + if (entry.getValue().values() == null) { + VirtualObject vobj = entry.getKey(); + CiValue[] values = new CiValue[vobj.fields().length]; + entry.getValue().setValues(values); + if (vobj.fields().length > 0) { + changed = true; + FloatingNode currentField = objectStates.get(vobj); + assert currentField != null; + do { + if (currentField instanceof VirtualObjectField) { + int index = ((VirtualObjectField) currentField).index(); + if (values[index] == null) { + values[index] = toCiValue(((VirtualObjectField) currentField).input()); + } + currentField = ((VirtualObjectField) currentField).lastState(); + } else { + assert currentField instanceof Phi : currentField; + currentField = (FloatingNode) ((Phi) currentField).valueAt(0); + } + } while (currentField != null); + } + } + } + } while (changed); } + return frame; } - CiFrame caller = null; - if (state.outerFrameState() != null) { - caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap); - } - return new CiFrame(caller, state.method, state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize()); } private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) { @@ -1983,7 +2029,7 @@ if (GraalOptions.TraceLinearScanLevel >= 3) { TTY.println("creating debug information at opId %d", opId); } - return computeFrameForState(state, opId, frameRefMap); + return new DebugFrameBuilder(state, opId, frameRefMap).build(); } private void assignLocations(List instructions, IntervalWalker iw) { diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java Wed Jul 06 17:02:38 2011 +0200 @@ -109,7 +109,7 @@ return; } - printer = new IdealGraphPrinter(stream); + printer = new IdealGraphPrinter(new BufferedOutputStream(stream)); if (GraalOptions.OmitDOTFrameStates) { printer.addOmittedClass(FrameState.class); } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Jul 06 17:02:38 2011 +0200 @@ -39,9 +39,11 @@ import com.oracle.max.graal.compiler.graph.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction; +import com.oracle.max.graal.compiler.ir.Phi.PhiType; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.compiler.value.FrameState.ValueProcedure; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.Bytecodes.MemoryBarriers; import com.sun.cri.ci.*; @@ -757,7 +759,7 @@ for (Node n : fixedGuard.inputs()) { if (n != null) { emitGuardComp((BooleanNode) n); - } + } } } @@ -781,14 +783,14 @@ if (comp instanceof Constant && comp.asConstant().asBoolean()) { // Nothing to emit. } else { - if (deoptimizationStubs == null) { - deoptimizationStubs = new ArrayList(); - } + if (deoptimizationStubs == null) { + deoptimizationStubs = new ArrayList(); + } - DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state); - deoptimizationStubs.add(stub); - emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info); - } + DeoptimizationStub stub = new DeoptimizationStub(DeoptAction.InvalidateReprofile, state); + deoptimizationStubs.add(stub); + emitBooleanBranch(comp, null, new LIRBlock(stub.label, stub.info), stub.info); + } } } @@ -1093,7 +1095,7 @@ lastState = fs; } else if (block.blockPredecessors().size() == 1) { FrameState fs = block.blockPredecessors().get(0).lastState(); - //assert fs != null : "B" + block.blockID() + ", pred=B" + block.blockPredecessors().get(0).blockID(); + assert fs != null; if (GraalOptions.TraceLIRGeneratorLevel >= 2) { TTY.println("STATE CHANGE (singlePred)"); if (GraalOptions.TraceLIRGeneratorLevel >= 3) { @@ -1513,7 +1515,7 @@ int nextSuccIndex = merge.phiPredecessorIndex(pred); PhiResolver resolver = new PhiResolver(this); for (Phi phi : merge.phis()) { - if (!phi.isDead()) { + if (phi.type() == PhiType.Value) { Value curVal = phi.valueAt(nextSuccIndex); if (curVal != null && curVal != phi) { if (curVal instanceof Phi) { @@ -1575,7 +1577,7 @@ } private CiValue operandForPhi(Phi phi) { - assert !phi.isDead() : "dead phi: " + phi.id(); + assert phi.type() == PhiType.Value : "wrong phi type: " + phi.id(); if (phi.operand().isIllegal()) { // allocate a variable for this phi createResultVariable(phi); @@ -1631,57 +1633,25 @@ } } - protected void walkState(Node x, FrameState state) { + protected void walkState(final Node x, FrameState state) { if (state == null) { return; } - walkState(x, state.outerFrameState()); - - for (int index = 0; index < state.stackSize(); index++) { - Value value = state.stackAt(index); - if (value != x) { - walkStateValue(value); - } - } - for (int index = 0; index < state.localsSize(); index++) { - final Value value = state.localAt(index); - if (value != null) { - if (!(value instanceof Phi && ((Phi) value).isDead())) { - walkStateValue(value); + state.forEachLiveStateValue(new ValueProcedure() { + public void doValue(Value value) { + if (value == x) { + // nothing to do, will be visited shortly + } else if (value instanceof Phi && ((Phi) value).type() == PhiType.Value) { + // phi's are special + operandForPhi((Phi) value); + } else if (value.operand().isIllegal()) { + // instruction doesn't have an operand yet + CiValue operand = makeOperand(value); + assert operand.isLegal() : "must be evaluated now"; } } - } - } - - private void walkStateValue(Value value) { - if (value != null) { - if (value instanceof VirtualObject) { - walkVirtualObject((VirtualObject) value); - } else if (value instanceof Phi && !((Phi) value).isDead()) { - // phi's are special - operandForPhi((Phi) value); - } else if (value.operand().isIllegal()) { - // instruction doesn't have an operand yet - CiValue operand = makeOperand(value); - assert operand.isLegal() : "must be evaluated now"; - } - } - } - - private void walkVirtualObject(VirtualObject value) { - if (value.input() instanceof Phi) { - assert !((Phi) value.input()).isDead(); - } - HashSet fields = new HashSet(); - VirtualObject obj = value; - do { - if (!fields.contains(obj.field().representation())) { - fields.add(obj.field().representation()); - walkStateValue(obj.input()); - } - obj = obj.object(); - } while (obj != null); + }); } protected LIRDebugInfo stateFor(Value x) { diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java Wed Jul 06 17:02:38 2011 +0200 @@ -62,9 +62,6 @@ } else if (visited.isMarked(phi)) { // break cycles in phis return phi; - } else if (phi.isDead()) { - // don't bother with illegals - return phi; } else { // attempt to simplify the phi by recursively simplifying its operands visited.mark(phi); @@ -74,20 +71,20 @@ for (int i = 0; i < max; i++) { Value oldInstr = phi.valueAt(i); - if (oldInstr == null || (oldInstr instanceof Phi && ((Phi) oldInstr).isDead())) { + if (oldInstr == null) { // if one operand is illegal, make the entire phi illegal - phi.makeDead(); visited.clear(phi); - return phi; + phi.replaceAndDelete(null); + return null; } Value newInstr = simplify(oldInstr); - if (newInstr == null || (newInstr instanceof Phi && ((Phi) newInstr).isDead())) { + if (newInstr == null) { // if the subst instruction is illegal, make the entire phi illegal - phi.makeDead(); visited.clear(phi); - return phi; + phi.replaceAndDelete(null); + return null; } // attempt to simplify this operand diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java Wed Jul 06 17:02:38 2011 +0200 @@ -23,6 +23,7 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; @@ -93,4 +94,27 @@ public Node copy(Graph into) { return new CheckCast(null, null, into); } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + CheckCast checkCast = (CheckCast) node; + Value object = checkCast.object(); + RiType exactType = object.exactType(); + if (exactType != null) { + return Constant.forBoolean(exactType.isSubtypeOf(checkCast.targetClass()), node.graph()); + } + CiConstant constant = object.asConstant(); + if (constant != null) { + assert constant.kind == CiKind.Object; + if (constant.isNull()) { + return Constant.forBoolean(true, node.graph()); + } else { + // this should never happen - non-null constants are always expected to provide an exactType + assert false; + } + } + return checkCast; + } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CreateVectorNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CreateVectorNode.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CreateVectorNode.java Wed Jul 06 17:02:38 2011 +0200 @@ -26,6 +26,7 @@ import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.ir.Phi.PhiType; import com.oracle.max.graal.compiler.phases.LoweringPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -98,7 +99,7 @@ EndNode end = new EndNode(graph()); LoopBegin loopBegin = new LoopBegin(graph()); loopBegin.addEnd(end); - Phi loopVariable = new Phi(CiKind.Int, loopBegin, graph()); + Phi loopVariable = new Phi(CiKind.Int, loopBegin, PhiType.Value, graph()); if (reversed) { IntegerSub add = new IntegerSub(CiKind.Int, loopVariable, Constant.forInt(1, graph()), graph()); diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java Wed Jul 06 17:02:38 2011 +0200 @@ -23,10 +23,12 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; +import com.sun.cri.ri.*; /** * The {@code InstanceOf} instruction represents an instanceof test. @@ -71,4 +73,36 @@ public Node copy(Graph into) { return new InstanceOf(null, null, nullIsTrue, into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + InstanceOf isInstance = (InstanceOf) node; + Value object = isInstance.object(); + RiType exactType = object.exactType(); + if (exactType != null) { + return Constant.forBoolean(exactType.isSubtypeOf(isInstance.targetClass()), node.graph()); + } + CiConstant constant = object.asConstant(); + if (constant != null) { + assert constant.kind == CiKind.Object; + if (constant.isNull()) { + return Constant.forBoolean(false, node.graph()); + } else { + // this should never happen - non-null constants are always expected to provide an exactType + assert false; + } + } + return isInstance; + } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsNonNull.java Wed Jul 06 17:02:38 2011 +0200 @@ -23,6 +23,7 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; @@ -67,7 +68,7 @@ */ public IsNonNull(Value object, Graph graph) { super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); - assert object == null || object.kind == CiKind.Object; + assert object == null || object.kind == CiKind.Object : object; setObject(object); } @@ -107,4 +108,30 @@ public Node copy(Graph into) { return new IsNonNull(null, into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + IsNonNull isNonNull = (IsNonNull) node; + Value object = isNonNull.object(); + if (object instanceof NewInstance || object instanceof NewArray) { + return Constant.forBoolean(true, node.graph()); + } + CiConstant constant = object.asConstant(); + if (constant != null) { + assert constant.kind == CiKind.Object; + return Constant.forBoolean(constant.isNonNull(), node.graph()); + } + return isNonNull; + } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IsType.java Wed Jul 06 17:02:38 2011 +0200 @@ -25,6 +25,7 @@ import java.util.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.CanonicalizerOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; @@ -127,4 +128,27 @@ public Node copy(Graph into) { return new IsType(null, type, into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static CanonicalizerOp CANONICALIZER = new CanonicalizerOp() { + @Override + public Node canonical(Node node) { + IsType isType = (IsType) node; + Value object = isType.object(); + RiType exactType = object.exactType(); + if (exactType != null) { + return Constant.forBoolean(exactType == isType.type, node.graph()); + } + // constants return the correct exactType, so they are handled by the code above + return isType; + } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java Wed Jul 06 17:02:38 2011 +0200 @@ -197,7 +197,7 @@ while (!hasPhisOnStack && i < state.stackSize()) { Value value = state.stackAt(i); hasPhisOnStack = isPhiAtBlock(value); - if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { + if (value != null) { i += value.kind.sizeInSlots(); } else { i++; @@ -208,7 +208,7 @@ Value value = state.localAt(i); hasPhisInLocals = isPhiAtBlock(value); // also ignore illegal HiWords - if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { + if (value != null) { i += value.kind.sizeInSlots(); } else { i++; @@ -227,11 +227,7 @@ if (value != null) { out.println(stateString(j, value)); // also ignore illegal HiWords - if (value instanceof Phi && ((Phi) value).isDead()) { - j += 1; - } else { - j += value.kind.sizeInSlots(); - } + j += value.kind.sizeInSlots(); } else { j++; } @@ -320,10 +316,7 @@ for (Node usage : usages()) { if (usage instanceof Phi) { - Phi phi = (Phi) usage; - if (!phi.isDead()) { - phi.removeInput(predIndex); - } + ((Phi) usage).removeInput(predIndex); } } } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Wed Jul 06 17:02:38 2011 +0200 @@ -36,8 +36,6 @@ */ public abstract class NewArray extends FixedNodeWithNext { - private static final EscapeOp ESCAPE = new NewArrayEscapeOp(); - private static final int INPUT_COUNT = 1; private static final int INPUT_LENGTH = 0; @@ -109,7 +107,7 @@ return super.lookup(clazz); } - private static class NewArrayEscapeOp implements EscapeOp { + private static final EscapeOp ESCAPE = new EscapeOp() { @Override public boolean canAnalyze(Node node) { @@ -207,31 +205,27 @@ } @Override - public EscapeField updateState(Node node, Node current, Map fields, Map fieldState) { + public int updateState(Node node, Node current, Map fieldIndex, Value[] fieldState) { if (current instanceof AccessIndexed) { int index = ((AccessIndexed) current).index().asConstant().asInt(); - EscapeField field = fields.get(index); if (current instanceof LoadIndexed) { LoadIndexed x = (LoadIndexed) current; if (x.array() == node) { - x.replaceAtUsages(fieldState.get(field)); + x.replaceAtUsages(fieldState[index]); assert x.usages().size() == 0; x.replaceAndDelete(x.next()); } } else if (current instanceof StoreIndexed) { StoreIndexed x = (StoreIndexed) current; if (x.array() == node) { - fieldState.put(field, x.value()); + fieldState[index] = x.value(); assert x.usages().size() == 0; - WriteMemoryCheckpointNode checkpoint = new WriteMemoryCheckpointNode(x.graph()); - checkpoint.setStateAfter(x.stateAfter()); - checkpoint.setNext(x.next()); - x.replaceAndDelete(checkpoint); - return field; + x.replaceAndDelete(x.next()); + return index; } } } - return null; + return -1; } - } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Wed Jul 06 17:02:38 2011 +0200 @@ -36,7 +36,6 @@ * The {@code NewInstance} instruction represents the allocation of an instance class object. */ public final class NewInstance extends FixedNodeWithNext { - private static final EscapeOp ESCAPE = new NewInstanceEscapeOp(); private static final int INPUT_COUNT = 0; private static final int SUCCESSOR_COUNT = 0; @@ -109,7 +108,7 @@ return super.lookup(clazz); } - private static class NewInstanceEscapeOp implements EscapeOp { + private static final EscapeOp ESCAPE = new EscapeOp() { @Override public boolean canAnalyze(Node node) { @@ -195,31 +194,27 @@ } @Override - public EscapeField updateState(Node node, Node current, Map fields, Map fieldState) { + public int updateState(Node node, Node current, Map fieldIndex, Value[] fieldState) { if (current instanceof AccessField) { - EscapeField field = fields.get(((AccessField) current).field()); - if (current instanceof LoadField) { - LoadField x = (LoadField) current; - if (x.object() == node) { - assert fieldState.get(field) != null : field + ", " + ((AccessField) current).field() + ((AccessField) current).field().hashCode(); - x.replaceAtUsages(fieldState.get(field)); + if (((AccessField) current).object() == node) { + Integer field = fieldIndex.get(((AccessField) current).field()); + assert field != null : ((AccessField) current).field() + " " + ((AccessField) current).field().hashCode(); + if (current instanceof LoadField) { + LoadField x = (LoadField) current; + assert fieldState[field] != null : field + ", " + ((AccessField) current).field() + ((AccessField) current).field().hashCode(); + x.replaceAtUsages(fieldState[field]); assert x.usages().size() == 0; x.replaceAndDelete(x.next()); - } - } else if (current instanceof StoreField) { - StoreField x = (StoreField) current; - if (x.object() == node) { - fieldState.put(field, x.value()); + } else if (current instanceof StoreField) { + StoreField x = (StoreField) current; + fieldState[field] = x.value(); assert x.usages().size() == 0; - WriteMemoryCheckpointNode checkpoint = new WriteMemoryCheckpointNode(x.graph()); - checkpoint.setStateAfter(x.stateAfter()); - checkpoint.setNext(x.next()); - x.replaceAndDelete(checkpoint); + x.replaceAndDelete(x.next()); return field; } } } - return null; + return -1; } - } + }; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java Wed Jul 06 17:02:38 2011 +0200 @@ -42,7 +42,7 @@ private static final int SUCCESSOR_COUNT = 0; - private boolean isDead; + private final PhiType type; @Override protected int inputCount() { @@ -66,21 +66,31 @@ inputs().set(super.inputCount() + INPUT_MERGE, n); } - public Phi(CiKind kind, Merge merge, Graph graph) { + public static enum PhiType { + Value, // normal value phis + Memory, // memory phis + Virtual // phis used for VirtualObjectField merges + } + + public Phi(CiKind kind, Merge merge, PhiType type, Graph graph) { super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.type = type; setMerge(merge); } - Phi(CiKind kind, Graph graph) { + private Phi(CiKind kind, PhiType type, Graph graph) { super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.type = type; + } + + public PhiType type() { + return type; } @Override public boolean verify() { assertTrue(merge() != null); - if (!isDead()) { - assertTrue(merge().phiPredecessorCount() == valueCount()); - } + assertTrue(merge().phiPredecessorCount() == valueCount(), merge().phiPredecessorCount() + "==" + valueCount()); return true; } @@ -111,17 +121,6 @@ v.visitPhi(this); } - /** - * Make this phi illegal if types were not merged correctly. - */ - public void makeDead() { - isDead = true; - } - - public boolean isDead() { - return isDead; - } - @Override public void print(LogStream out) { out.print("phi function ("); @@ -143,10 +142,10 @@ } str.append(valueAt(i) == null ? "-" : valueAt(i).id()); } - if (isDead()) { - return "Phi: dead (" + str + ")"; + if (type == PhiType.Value) { + return "Phi: (" + str + ")"; } else { - return "Phi: (" + str + ")"; + return type + "Phi: (" + str + ")"; } } @@ -160,8 +159,7 @@ @Override public Node copy(Graph into) { - Phi x = new Phi(kind, into); - x.isDead = isDead; + Phi x = new Phi(kind, type, into); return x; } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java Wed Jul 06 17:02:38 2011 +0200 @@ -33,9 +33,7 @@ public class VirtualObject extends FloatingNode { - private static final int INPUT_COUNT = 2; - private static final int INPUT_OBJECT = 0; - private static final int INPUT_INPUT = 1; + private static final int INPUT_COUNT = 0; private static final int SUCCESSOR_COUNT = 0; @@ -49,48 +47,13 @@ return super.successorCount() + SUCCESSOR_COUNT; } - /** - * The instruction that specifies the old state of the virtual object. - */ - public VirtualObject object() { - return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - private VirtualObject setObject(VirtualObject n) { - return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - /** - * The instruction that contains the new state of the specified field. - */ - public Value input() { - return (Value) inputs().get(super.inputCount() + INPUT_INPUT); - } - - public Value setInput(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n); - } - - private EscapeField field; private EscapeField[] fields; private RiType type; - /** - * Constructs a new ArrayLength instruction. - * @param array the instruction producing the array - * @param newFrameState the state after executing this instruction - */ - public VirtualObject(VirtualObject object, Value input, EscapeField field, RiType type, EscapeField[] fields, Graph graph) { + public VirtualObject(RiType type, EscapeField[] fields, Graph graph) { super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.field = field; this.type = type; this.fields = fields; - setObject(object); - setInput(input); - } - - public EscapeField field() { - return field; } public RiType type() { @@ -110,23 +73,22 @@ public Map getDebugProperties() { Map properties = super.getDebugProperties(); properties.put("type", type); - properties.put("field", field); return properties; } @Override public String shortName() { - return "VirtualObject " + field.name(); + return "VirtualObject " + type.name(); } @Override public void print(LogStream out) { - out.print(object()).print(".").print(field.name()).print("=").print(input()); + out.print("virtualobject ").print(type.name()); } @Override public Node copy(Graph into) { - VirtualObject x = new VirtualObject(null, null, field, type, fields, into); + VirtualObject x = new VirtualObject(type, fields, into); return x; } } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObjectField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObjectField.java Wed Jul 06 17:02:38 2011 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + + +public class VirtualObjectField extends FloatingNode { + + private static final int INPUT_COUNT = 3; + private static final int INPUT_OBJECT = 0; + private static final int INPUT_LAST_STATE = 1; + private static final int INPUT_INPUT = 2; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that specifies the virtual object instance. + */ + public VirtualObject object() { + return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + private VirtualObject setObject(VirtualObject n) { + return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * The instruction that specifies the old state of the virtual object. + */ + public FloatingNode lastState() { + return (FloatingNode) inputs().get(super.inputCount() + INPUT_LAST_STATE); + } + + private FloatingNode setLastState(FloatingNode n) { + return (FloatingNode) inputs().set(super.inputCount() + INPUT_LAST_STATE, n); + } + + /** + * The instruction that contains the new state of the specified field. + */ + public Value input() { + return (Value) inputs().get(super.inputCount() + INPUT_INPUT); + } + + public Value setInput(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n); + } + + private int index; + + /** + * Constructs a new ArrayLength instruction. + * @param array the instruction producing the array + * @param newFrameState the state after executing this instruction + */ + public VirtualObjectField(VirtualObject object, FloatingNode lastState, Value input, int index, Graph graph) { + super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.index = index; + setObject(object); + setLastState(lastState); + setInput(input); + } + + public int index() { + return index; + } + + @Override + public void accept(ValueVisitor v) { + // nothing to do... + } + + @Override + public Map getDebugProperties() { + Map properties = super.getDebugProperties(); + properties.put("index", index); + return properties; + } + + @Override + public String shortName() { + return "VirtualObjectField " + object().fields()[index].name(); + } + + @Override + public void print(LogStream out) { + out.print(object()).print(".").print(object().fields()[index].name()).print("=").print(input()); + } + + @Override + public Node copy(Graph into) { + VirtualObjectField x = new VirtualObjectField(null, null, null, index, into); + return x; + } +} diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Wed Jul 06 17:02:38 2011 +0200 @@ -77,8 +77,8 @@ if (current instanceof AbstractVectorNode) { for (Node usage : current.usages()) { flood.add(usage); - } - } + } + } } } @@ -105,29 +105,29 @@ endNode.replaceAndDelete(loop.next()); loop.delete(); } - } else if (node instanceof Merge) { - for (Node n : node.usages()) { - if (n instanceof Phi) { - Phi phi = (Phi) n; - if (phi.usages().size() == 1 && phi.usages().get(0) instanceof VirtualObject) { - // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the store that produced it) is dead! => fix this in escape analysis - VirtualObject virtualObject = (VirtualObject) phi.usages().get(0); - virtualObject.replaceAndDelete(virtualObject.object()); - } - } - } - } - - - if (IdentifyBlocksPhase.isFixed(node)) { - for (Node n : new ArrayList(node.usages())) { - if (n instanceof VirtualObject) { - // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the - // store that produced it) is dead! => fix this in Escape analysis - VirtualObject virtualObject = (VirtualObject) n; - virtualObject.replaceAndDelete(virtualObject.object()); - } - } +// } else if (node instanceof Merge) { +// for (Node n : node.usages()) { +// if (n instanceof Phi) { +// Phi phi = (Phi) n; +// if (phi.usages().size() == 1 && phi.usages().get(0) instanceof VirtualObject) { +// // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the store that produced it) is dead! => fix this in escape analysis +// VirtualObject virtualObject = (VirtualObject) phi.usages().get(0); +// virtualObject.replaceAndDelete(virtualObject.object()); +// } +// } +// } +// } +// +// +// if (IdentifyBlocksPhase.isFixed(node)) { +// for (Node n : new ArrayList(node.usages())) { +// if (n instanceof VirtualObject) { +// // (tw) This VirtualObject instance is implicitely dead, because the CFG to it (i.e. the +// // store that produced it) is dead! => fix this in Escape analysis +// VirtualObject virtualObject = (VirtualObject) n; +// virtualObject.replaceAndDelete(virtualObject.object()); +// } +// } } } } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Wed Jul 06 17:02:38 2011 +0200 @@ -23,13 +23,13 @@ package com.oracle.max.graal.compiler.phases; import java.util.*; -import java.util.Map.Entry; import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.gen.*; import com.oracle.max.graal.compiler.graph.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.*; import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.compiler.value.*; @@ -40,24 +40,277 @@ public class EscapeAnalysisPhase extends Phase { + public interface MergeableState { + T clone(); + void merge(Merge merge, Collection withStates); + void loopBegin(LoopBegin loopBegin); + void loopEnd(LoopEnd loopEnd, T loopEndState); + } - public static class BlockExitState { - public final Map fieldState; - public VirtualObject obj; + public abstract static class PostOrderNodeIterator> { + + private final NodeBitMap visitedEnds; + private final Deque nodeQueue; + private final HashMap nodeStates; + private final FixedNode start; + + protected T state; + + public PostOrderNodeIterator(FixedNode start, T initialState) { + visitedEnds = start.graph().createNodeBitMap(); + nodeQueue = new ArrayDeque(); + nodeStates = new HashMap(); + this.start = start; + this.state = initialState; + } + + public void apply(FixedNode start) { + FixedNode current = start; + + do { + if (current instanceof Invoke) { + invoke((Invoke) current); + queueSuccessors(current); + current = nextQueuedNode(); + } else if (current instanceof LoopBegin) { + state.loopBegin((LoopBegin) current); + nodeStates.put(current, state.clone()); + loopBegin((LoopBegin) current); + current = ((LoopBegin) current).next(); + assert current != null; + } else if (current instanceof LoopEnd) { + T loopBeginState = nodeStates.get(((LoopEnd) current).loopBegin()); + if (loopBeginState != null) { + loopBeginState.loopEnd((LoopEnd) current, state); + } + loopEnd((LoopEnd) current); + current = nextQueuedNode(); + } else if (current instanceof Merge) { + merge((Merge) current); + current = ((Merge) current).next(); + assert current != null; + } else if (current instanceof FixedNodeWithNext) { + FixedNode next = ((FixedNodeWithNext) current).next(); + node(current); + current = next; + assert current != null; + } else if (current instanceof EndNode) { + end((EndNode) current); + queueMerge((EndNode) current); + current = nextQueuedNode(); + } else if (current instanceof Deoptimize) { + deoptimize((Deoptimize) current); + current = nextQueuedNode(); + } else if (current instanceof Return) { + returnNode((Return) current); + current = nextQueuedNode(); + } else if (current instanceof Unwind) { + unwind((Unwind) current); + current = nextQueuedNode(); + } else if (current instanceof ControlSplit) { + controlSplit((ControlSplit) current); + queueSuccessors(current); + current = nextQueuedNode(); + } else { + assert false : current.shortName(); + } + } while(current != null); + } + + private void queueSuccessors(FixedNode x) { + nodeStates.put(x, state); + for (Node node : x.successors()) { + if (node != null) { + nodeQueue.addFirst((FixedNode) node); + } + } + } - public BlockExitState() { - this.fieldState = new HashMap(); + private FixedNode nextQueuedNode() { + int maxIterations = nodeQueue.size(); + while (maxIterations-- > 0) { + FixedNode node = nodeQueue.removeFirst(); + if (node instanceof Merge) { + Merge merge = (Merge) node; + state = nodeStates.get(merge.endAt(0)).clone(); + ArrayList states = new ArrayList(merge.endCount() - 1); + for (int i = 1; i < merge.endCount(); i++) { + T other = nodeStates.get(merge.endAt(i)); + assert other != null; + states.add(other); + } + state.merge(merge, states); + return merge; + } else { + assert node.predecessors().size() == 1; + state = nodeStates.get(node.predecessors().get(0)).clone(); + return node; + } + } + return null; + } + + private void queueMerge(EndNode end) { + assert !visitedEnds.isMarked(end); + assert !nodeStates.containsKey(end); + nodeStates.put(end, state); + visitedEnds.mark(end); + Merge merge = end.merge(); + boolean endsVisited = true; + for (int i = 0; i < merge.endCount(); i++) { + if (!visitedEnds.isMarked(merge.endAt(i))) { + endsVisited = false; + break; + } + } + if (endsVisited) { + nodeQueue.add(merge); + } + } + + protected abstract void node(FixedNode node); + + protected void end(EndNode endNode) { + node(endNode); + } + + protected void merge(Merge merge) { + node(merge); + } + + protected void loopBegin(LoopBegin loopBegin) { + node(loopBegin); + } + + protected void loopEnd(LoopEnd loopEnd) { + node(loopEnd); + } + + protected void deoptimize(Deoptimize deoptimize) { + node(deoptimize); + } + + protected void controlSplit(ControlSplit controlSplit) { + node(controlSplit); + } + + protected void returnNode(Return returnNode) { + node(returnNode); + } + + protected void invoke(Invoke invoke) { + node(invoke); + } + + protected void unwind(Unwind unwind) { + node(unwind); } } + public static class BlockExitState implements MergeableState { + public final Value[] fieldState; + public final VirtualObject virtualObject; + public FloatingNode virtualObjectField; + + public BlockExitState(EscapeField[] fields, VirtualObject virtualObject) { + this.fieldState = new Value[fields.length]; + this.virtualObject = virtualObject; + this.virtualObjectField = null; + for (int i = 0; i < fields.length; i++) { + fieldState[i] = Constant.defaultForKind(fields[i].kind(), virtualObject.graph()); + virtualObjectField = new VirtualObjectField(virtualObject, virtualObjectField, fieldState[i], i, virtualObject.graph()); + } + } + + public BlockExitState(BlockExitState state) { + this.fieldState = state.fieldState.clone(); + this.virtualObject = state.virtualObject; + this.virtualObjectField = state.virtualObjectField; + } + + public void updateField(int fieldIndex) { + virtualObjectField = new VirtualObjectField(virtualObject, virtualObjectField, fieldState[fieldIndex], fieldIndex, virtualObject.graph()); + } + + @Override + public BlockExitState clone() { + return new BlockExitState(this); + } + + @Override + public void merge(Merge merge, Collection withStates) { + Phi vobjPhi = null; + Phi[] valuePhis = new Phi[fieldState.length]; + for (BlockExitState other : withStates) { + if (virtualObjectField != other.virtualObjectField && vobjPhi == null) { + vobjPhi = new Phi(CiKind.Illegal, merge, PhiType.Virtual, virtualObject.graph()); + vobjPhi.addInput(virtualObjectField); + virtualObjectField = vobjPhi; + } + for (int i2 = 0; i2 < fieldState.length; i2++) { + if (fieldState[i2] != other.fieldState[i2] && valuePhis[i2] == null) { + valuePhis[i2] = new Phi(fieldState[i2].kind, merge, PhiType.Value, virtualObject.graph()); + valuePhis[i2].addInput(fieldState[i2]); + fieldState[i2] = valuePhis[i2]; + } + } + } + for (BlockExitState other : withStates) { + if (vobjPhi != null) { + vobjPhi.addInput(other.virtualObjectField); + } + for (int i2 = 0; i2 < fieldState.length; i2++) { + if (valuePhis[i2] != null) { + valuePhis[i2].addInput(other.fieldState[i2]); + } + } + } + assert vobjPhi == null || vobjPhi.valueCount() == withStates.size() + 1; + for (int i2 = 0; i2 < fieldState.length; i2++) { + if (valuePhis[i2] != null) { + virtualObjectField = new VirtualObjectField(virtualObject, virtualObjectField, valuePhis[i2], i2, virtualObject.graph()); + assert valuePhis[i2].valueCount() == withStates.size() + 1; + } + } + } + + @Override + public void loopBegin(LoopBegin loopBegin) { + Phi vobjPhi = null; + vobjPhi = new Phi(CiKind.Illegal, loopBegin, PhiType.Virtual, virtualObject.graph()); + vobjPhi.addInput(virtualObjectField); + virtualObjectField = vobjPhi; + for (int i2 = 0; i2 < fieldState.length; i2++) { + Phi valuePhi = new Phi(fieldState[i2].kind, loopBegin, PhiType.Value, virtualObject.graph()); + valuePhi.addInput(fieldState[i2]); + fieldState[i2] = valuePhi; + updateField(i2); + } + } + + @Override + public void loopEnd(LoopEnd x, BlockExitState loopEndState) { + while (!(virtualObjectField instanceof Phi)) { + virtualObjectField = ((VirtualObjectField) virtualObjectField).lastState(); + } + ((Phi) virtualObjectField).addInput(loopEndState.virtualObjectField); + assert ((Phi) virtualObjectField).valueCount() == 2; + for (int i2 = 0; i2 < fieldState.length; i2++) { + ((Phi) fieldState[i2]).addInput(loopEndState.fieldState[i2]); + assert ((Phi) fieldState[i2]).valueCount() == 2; + } + } + } + + public class EscapementFixup { private List blocks; - private final Map fields = new HashMap(); + private final Map fields = new HashMap(); private final Map exitStates = new HashMap(); private final EscapeOp op; - private Graph graph; + private final Graph graph; private final Node node; private RiType type; private EscapeField[] escapeFields; @@ -74,217 +327,36 @@ } public void removeAllocation() { - final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true); - identifyBlocksPhase.apply(graph); - blocks = identifyBlocksPhase.getBlocks(); + assert node instanceof FixedNodeWithNext; - final HashMap phis = new HashMap(); - final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node); - assert startBlock != null; type = ((Value) node).exactType(); escapeFields = op.fields(node); - for (EscapeField field : escapeFields) { - fields.put(field.representation(), field); + for (int i = 0; i < escapeFields.length; i++) { + fields.put(escapeFields[i].representation(), i); } - - Block.iteratePostOrder(blocks, new BlockClosure() { - - public void apply(Block block) { - if (GraalOptions.TraceEscapeAnalysis) { - TTY.println("Block %d", block.blockID()); - } -// for (Node n : block.getInstructions()) { -// TTY.println(" %d %s", n.id(), n.shortName()); -// } -// for (Block b : block.getSuccessors()) { -// TTY.print(" %d", b.blockID()); -// } -// TTY.println(); - - BlockExitState state = new BlockExitState(); - if (/*block == startBlock ||*/ block.getPredecessors().size() == 0) { - state.obj = null; - } else { - List predecessors = block.getPredecessors(); - Set mergedFields = new HashSet(); - - BlockExitState predState = exitStates.get(predecessors.get(0)); - state.obj = predState == null ? null : predState.obj; - - for (int i = 0; i < predecessors.size(); i++) { - BlockExitState exitState = exitStates.get(predecessors.get(i)); - if (exitState == null) { - // (tw) What about an object that is allocated in a loop. We are merging in the values of the old allocation?; Now solved by "if" below. - mergedFields.addAll(fields.values()); - state.obj = null; - break; - } else { - for (EscapeField field : fields.values()) { - if (state.fieldState.get(field) == null) { - state.fieldState.put(field, exitState.fieldState.get(field)); - if (i != 0) { - // We need to merge this field too! - mergedFields.add(field); - } - } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) { - mergedFields.add(field); - } - } - } - } - if (block.firstNode() instanceof LoopBegin) { - if (predState.obj == null) { - state.obj = null; - mergedFields.clear(); - } - } - - if (!mergedFields.isEmpty()) { - assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id(); - for (EscapeField field : mergedFields) { - Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph); - state.fieldState.put(field, phi); - phis.put(phi, field); - state.obj = new VirtualObject(state.obj, phi, field, type, escapeFields, graph); - } - } - } + final VirtualObject virtual = new VirtualObject(type, escapeFields, graph); + final BlockExitState startState = new BlockExitState(escapeFields, virtual); + if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { + TTY.println("new virtual object: " + virtual); + } + node.replaceAtUsages(virtual); + final FixedNode next = ((FixedNodeWithNext) node).next(); + node.replaceAndDelete(next); - Node current; - if (block.firstNode() instanceof StartNode) { - current = ((StartNode) block.firstNode()).next(); - } else { - current = block.firstNode(); - } - while (current != block.lastNode()) { - Node next = ((FixedNodeWithNext) current).next(); - FrameState stateAfter = null; - if (current instanceof StateSplit) { - stateAfter = ((StateSplit) current).stateAfter(); - } - if (current == node) { - for (EscapeField field : fields.values()) { - Constant value = Constant.defaultForKind(field.kind(), graph); - state.fieldState.put(field, value); - state.obj = new VirtualObject(state.obj, value, field, type, escapeFields, graph); - } - } else { - EscapeField changedField = op.updateState(node, current, fields, state.fieldState); - if (changedField != null) { - state.obj = new VirtualObject(state.obj, state.fieldState.get(changedField), changedField, type, escapeFields, graph); - } - } - if (stateAfter != null) { - updateFrameState(stateAfter, state.obj); - } - current = next; + new PostOrderNodeIterator(next, startState) { + @Override + protected void node(FixedNode node) { + int changedField = op.updateState(virtual, node, fields, state.fieldState); + if (changedField != -1) { + state.updateField(changedField); } - - if (GraalOptions.TraceEscapeAnalysis) { - TTY.print(" block end state: "); - for (Entry entry : state.fieldState.entrySet()) { - TTY.print("%s->%s ", entry.getKey().name(), entry.getValue()); - } - TTY.println(); - } - exitStates.put(block, state); - } - }); - - for (Entry entry : phis.entrySet()) { - Phi phi = entry.getKey(); - EscapeField field = entry.getValue(); - Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge()); - - List predecessors = block.getPredecessors(); - assert predecessors.size() > 0; - Node simple = exitStates.get(predecessors.get(0)).fieldState.get(field); - for (int i = 1; i < predecessors.size(); i++) { - BlockExitState exitState = exitStates.get(predecessors.get(i)); - if (exitState.fieldState.get(field) != simple) { - simple = null; - break; - } - } - if (simple != null) { - // (tw) Should never be reached, because Phi verification fails here.. - phi.replaceAndDelete(simple); - } else { - for (int i = 0; i < predecessors.size(); i++) { - BlockExitState exitState = exitStates.get(predecessors.get(i)); - assert exitState != null; - Node value = exitState.fieldState.get(field); - if (GraalOptions.TraceEscapeAnalysis) { - TTY.println("fixing phi %d with %s", phi.id(), value); - } - if (value == null) { - phi.addInput(Constant.defaultForKind(field.kind(), graph)); - } else { - phi.addInput(value); + if (!node.isDeleted() && node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { + if (state.virtualObjectField != null) { + ((StateSplit) node).stateAfter().addVirtualObjectMapping(state.virtualObjectField); } } } - } - // the rest of the usages should be dead frame states... - for (Node usage : new ArrayList(node.usages())) { - if (usage instanceof IsNonNull) { - usage.replaceAndDelete(Constant.forBoolean(true, graph)); - } else if (usage instanceof RegisterFinalizer) { - usage.replaceAndDelete(((RegisterFinalizer) usage).next()); - } else { - assert usage instanceof FrameState || usage instanceof VirtualObject : "usage: " + usage; - usage.inputs().replace(node, Node.Null); - } - } - - if (node instanceof FixedNodeWithNext) { - node.replaceAndDelete(((FixedNodeWithNext) node).next()); - } else { - node.delete(); - } - } - - private void updateFrameState(FrameState frameState, VirtualObject current) { - for (int i = 0; i < frameState.inputs().size(); i++) { - if (frameState.inputs().get(i) == node) { - frameState.inputs().set(i, current); - } else if (frameState.inputs().get(i) instanceof VirtualObject) { - VirtualObject obj = (VirtualObject) frameState.inputs().get(i); - do { - updateVirtualObject(obj, current); - obj = obj.object(); - } while (obj != null); - } - } - FrameState outer = frameState.outerFrameState(); - if (outer != null) { - boolean duplicate = false; - for (int i = 0; i < outer.inputs().size(); i++) { - if (outer.inputs().get(i) == node) { - duplicate = true; - } - } - // (tw) need to fully duplicate also if there is a reference to "node" in an outer framestate? - duplicate = true; - if (duplicate) { - outer = outer.duplicate(outer.bci); - frameState.setOuterFrameState(outer); - } - updateFrameState(outer, current); - } - } - - private void updateVirtualObject(VirtualObject obj, VirtualObject current) { - if (obj.input() == node) { - // (tw) don't we have similar issues here like in framestate dup? We are updating a shared data structure here.. - obj.setInput(current); - } else if (obj.input() instanceof VirtualObject) { - VirtualObject obj2 = (VirtualObject) obj.input(); - do { - updateVirtualObject(obj2, current); - obj2 = obj2.object(); - } while (obj2 != null); - } + }.apply(next); } private void process() { @@ -305,9 +377,6 @@ @Override protected void run(Graph graph) { - if (compilation.method.name().contains("removeEnd") || compilation.method.name().contains("emitCode")) { - return; - } for (Node node : graph.getNodes()) { EscapeOp op = node.lookup(EscapeOp.class); if (op != null && op.canAnalyze(node)) { @@ -344,10 +413,10 @@ TTY.println("%n!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method); } new EscapementFixup(op, graph, node).apply(); + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After escape", graph, true, false)); + } new PhiSimplifier(graph); - if (compilation.compiler.isObserved()) { - compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After escape " + node.id(), graph, true, false)); - } break; } if (weight < minimumWeight) { @@ -364,6 +433,12 @@ } new InliningPhase(compilation, ir, invokes).apply(graph); new DeadCodeEliminationPhase().apply(graph); + if (node.isDeleted()) { + if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { + TTY.println("%n!!!!!!!! object died while performing escape analysis: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method); + } + break; + } exits.clear(); invokes.clear(); } while (iterations++ < 3); @@ -433,7 +508,7 @@ void beforeUpdate(Node node, Node usage); - EscapeField updateState(Node node, Node current, Map fields, Map fieldState); + int updateState(Node node, Node current, Map fieldIndex, Value[] fieldState); } } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java Wed Jul 06 17:02:38 2011 +0200 @@ -26,6 +26,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.PhiType; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.compiler.util.LoopUtil.Loop; import com.oracle.max.graal.compiler.value.*; @@ -93,7 +94,7 @@ IntegerSub sub = new IntegerSub(kind, c2.init(), c1.init(), graph); IntegerAdd addStride = new IntegerAdd(kind, sub, c1.stride(), graph); IntegerAdd add = new IntegerAdd(kind, c1, addStride, graph); - Phi phi = new Phi(kind, loopBegin, graph); // (gd) assumes order on loopBegin preds - works in collab with graph builder + Phi phi = new Phi(kind, loopBegin, PhiType.Value, graph); // (gd) assumes order on loopBegin preds - works in collab with graph builder phi.addInput(c2.init()); phi.addInput(add); c2.replaceAndDelete(phi); diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/MemoryPhase.java Wed Jul 06 17:02:38 2011 +0200 @@ -28,6 +28,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -155,8 +156,7 @@ assert phi.valueCount() <= phi.merge().endCount(); return original; } else { - Phi phi = new Phi(CiKind.Illegal, m, m.graph()); - phi.makeDead(); // Phi does not produce a value, it is only a memory phi. + Phi phi = new Phi(CiKind.Illegal, m, PhiType.Memory, m.graph()); for (int i = 0; i < mergeOperationCount + 1; ++i) { phi.addInput(original); } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java Wed Jul 06 17:02:38 2011 +0200 @@ -308,10 +308,11 @@ assert mergeBlock != null : "no block for merge " + merge.id(); for (int i = 0; i < phi.valueCount(); ++i) { if (phi.valueAt(i) == n) { - if (mergeBlock.getPredecessors().size() == 0) { + if (mergeBlock.getPredecessors().size() <= i) { TTY.println(merge.toString()); TTY.println(phi.toString()); TTY.println(merge.phiPredecessors().toString()); + TTY.println(phi.inputs().toString()); TTY.println("value count: " + phi.valueCount()); } block = getCommonDominator(block, mergeBlock.getPredecessors().get(i)); diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Jul 06 17:02:38 2011 +0200 @@ -364,7 +364,7 @@ return; } - assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode); + assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode) + ", x: " + x.x() + ", y: " + x.y() + ", kind: " + x.kind; switch (x.kind) { case Float: case Double: diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java Wed Jul 06 17:02:38 2011 +0200 @@ -27,6 +27,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.*; import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.compiler.util.GraphUtil.ColorSplitingLambda; @@ -153,7 +154,7 @@ for (Node usage : n.dataUsages()) { if (usage instanceof Phi) { // filter out data graph cycles Phi phi = (Phi) usage; - if (!phi.isDead()) { + if (phi.type() == PhiType.Value) { Merge merge = phi.merge(); if (merge instanceof LoopBegin) { LoopBegin phiLoop = (LoopBegin) merge; @@ -172,7 +173,7 @@ markWithState(n, inOrBefore); if (n instanceof Phi) { // filter out data graph cycles Phi phi = (Phi) n; - if (!phi.isDead()) { + if (phi.type() == PhiType.Value) { int backIndex = -1; Merge merge = phi.merge(); if (!loopNodes.isMarked(merge) && merge instanceof LoopBegin) { @@ -489,7 +490,7 @@ values.add(valueAt); } if (createPhi) { - Phi phi = new Phi(kind, merge, merge.graph()); + Phi phi = new Phi(kind, merge, PhiType.Value, merge.graph()); valueMap.set(point, phi); for (EndNode end : merge.cfgPredecessors()) { phi.addInput(getValueAt(colors.get(end), valueMap, kind)); @@ -642,7 +643,7 @@ } if (n instanceof Phi) { // filter out data graph cycles Phi phi = (Phi) n; - if (!phi.isDead()) { + if (phi.type() == PhiType.Value) { int backIndex = -1; Merge merge = phi.merge(); if (!loopNodes.isNew(merge) && !loopNodes.isMarked(merge) && merge instanceof LoopBegin) { diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Wed Jul 06 17:02:38 2011 +0200 @@ -29,6 +29,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -128,12 +129,27 @@ return method; } + public void addVirtualObjectMapping(Node virtualObject) { + assert virtualObject instanceof VirtualObjectField || virtualObject instanceof Phi : virtualObject; + inputs().variablePart().add(virtualObject); + } + + public int virtualObjectMappingCount() { + return inputs().variablePart().size(); + } + + public Node virtualObjectMappingAt(int i) { + return inputs().variablePart().get(i); + } + + /** * Gets a copy of this frame state. */ public FrameState duplicate(int bci) { FrameState other = new FrameState(method, bci, localsSize, stackSize, locksSize, rethrowException, graph()); other.inputs().setAll(inputs()); + other.inputs().variablePart().addAll(inputs().variablePart()); other.setOuterFrameState(outerFrameState()); return other; } @@ -165,6 +181,7 @@ for (int i = 0; i < locksSize; i++) { other.setValueAt(localsSize + other.stackSize + i, lockAt(i)); } + other.inputs().variablePart().addAll(inputs().variablePart()); other.setOuterFrameState(outerFrameState()); return other; } @@ -317,7 +334,7 @@ return phi; } } - Phi phi = new Phi(p.kind, block, graph()); + Phi phi = new Phi(p.kind, block, PhiType.Value, graph()); setValueAt(localsSize + i, phi); return phi; } @@ -337,7 +354,7 @@ return phi; } } - Phi phi = new Phi(p.kind, block, graph()); + Phi phi = new Phi(p.kind, block, PhiType.Value, graph()); storeLocal(i, phi); return phi; } @@ -385,11 +402,9 @@ Value y = other.valueAt(i); if (x != y || ((x instanceof Phi) && ((Phi) x).merge() == block)) { if (typeMismatch(x, y)) { - if (x instanceof Phi) { - Phi phi = (Phi) x; - if (phi.merge() == block) { - phi.makeDead(); - } + if ((x instanceof Phi) && ((Phi) x).merge() == block) { + x.replaceAtUsages(null); + x.delete(); } setValueAt(i, null); continue; @@ -471,30 +486,83 @@ * @param proc the call back called to process each live value traversed */ public void forEachLiveStateValue(ValueProcedure proc) { - for (int i = 0; i < valuesSize(); i++) { - Value value = valueAt(i); - visitLiveStateValue(value, proc); - } - if (outerFrameState() != null) { - outerFrameState().forEachLiveStateValue(proc); - } - } + HashSet vobjs = null; + FrameState current = this; + do { + for (int i = 0; i < current.valuesSize(); i++) { + Value value = current.valueAt(i); + if (value instanceof VirtualObject) { + if (vobjs == null) { + vobjs = new HashSet(); + } + vobjs.add((VirtualObject) value); + } else if (value != null) { + proc.doValue(value); + } + } + current = current.outerFrameState(); + } while (current != null); + + if (vobjs != null) { + // collect all VirtualObjectField instances: + HashMap objectStates = new HashMap(); + current = this; + do { + for (int i = 0; i < current.virtualObjectMappingCount(); i++) { + VirtualObjectField field = (VirtualObjectField) current.virtualObjectMappingAt(i); + // null states occur for objects with 0 fields + if (field != null && !objectStates.containsKey(field.object())) { + objectStates.put(field.object(), field); + } + } + current = current.outerFrameState(); + } while (current != null); - private void visitLiveStateValue(Value value, ValueProcedure proc) { - if (value != null) { - if (value instanceof VirtualObject) { - HashSet fields = new HashSet(); - VirtualObject obj = (VirtualObject) value; - do { - if (!fields.contains(obj.field().representation())) { - fields.add(obj.field().representation()); - visitLiveStateValue(obj.input(), proc); + do { + HashSet vobjsCopy = new HashSet(vobjs); + for (VirtualObject vobj : vobjsCopy) { + if (vobj.fields().length > 0) { + boolean[] fieldState = new boolean[vobj.fields().length]; + FloatingNode currentField = objectStates.get(vobj); + assert currentField != null : this; + do { + if (currentField instanceof VirtualObjectField) { + int index = ((VirtualObjectField) currentField).index(); + Value value = ((VirtualObjectField) currentField).input(); + if (!fieldState[index]) { + fieldState[index] = true; + if (value instanceof VirtualObject) { + vobjs.add((VirtualObject) value); + } else { + proc.doValue(value); + } + } + currentField = ((VirtualObjectField) currentField).lastState(); + } else { + assert currentField instanceof Phi : currentField; + currentField = (FloatingNode) ((Phi) currentField).valueAt(0); + } + } while (currentField != null); } - obj = obj.object(); - } while (obj != null); - } else { - proc.doValue(value); + vobjs.remove(vobj); + } + } while (!vobjs.isEmpty()); + if (!vobjs.isEmpty()) { + for (VirtualObject obj : vobjs) { + TTY.println("+" + obj); + } + for (Node vobj : inputs().variablePart()) { + if (vobj instanceof VirtualObjectField) { + TTY.println("-" + ((VirtualObjectField) vobj).object()); + } else { + TTY.println("-" + vobj); + } + } + for (Node n : this.usages()) { + TTY.println("usage: " + n); + } } + assert vobjs.isEmpty() : "at FrameState " + this; } } diff -r 132aa6f2bbc0 -r adbb7bca84b7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java Wed Jul 06 17:02:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java Wed Jul 06 17:02:38 2011 +0200 @@ -28,6 +28,7 @@ import java.util.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.ir.Phi.PhiType; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -334,8 +335,11 @@ public Value loadLocal(int i) { Value x = locals[i]; if (x != null) { - if (x instanceof Phi && ((Phi) x).isDead()) { - return null; + if (x instanceof Phi) { + assert ((Phi) x).type() == PhiType.Value; + if (x.isDeleted()) { + return null; + } } assert x.kind.isSingleWord() || locals[i + 1] == null || locals[i + 1] instanceof Phi; }