# HG changeset patch # User Christian Wimmer # Date 1330992589 28800 # Node ID 74f47ef373942ae5c55b5f492db75f4076c0109a # Parent a775efb8fcec217f10042605698df724c2314550 Fix and enable liveness analysis to prune unnecessary frame state entries diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Mar 05 16:09:49 2012 -0800 @@ -186,7 +186,7 @@ public static boolean OptReorderLoops = true; public static boolean OptEliminateGuards = true; public static boolean OptImplicitNullChecks = true; - public static boolean OptLivenessAnalysis = false; + public static boolean OptLivenessAnalysis = true; /** * Flag to turn on SSA-based register allocation, which is currently under development. diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Mon Mar 05 16:09:49 2012 -0800 @@ -27,6 +27,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.graal.compiler.gen.LIRGenerator.LockScope; +import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.lir.*; import com.oracle.max.graal.nodes.*; @@ -151,18 +152,22 @@ ciObj = CiVirtualObject.get(obj.type(), null, virtualObjects.size()); virtualObjects.put(obj, ciObj); } + Debug.metric("StateVirtualObjects").increment(); return ciObj; } else if (value instanceof ConstantNode) { + Debug.metric("StateConstants").increment(); return ((ConstantNode) value).value; } else if (value != null) { + Debug.metric("StateVariables").increment(); CiValue operand = nodeOperands.get(value); assert operand != null && (operand instanceof Variable || operand instanceof CiConstant); return operand; } else { // return a dummy value because real value not needed + Debug.metric("StateIllegals").increment(); return CiValue.IllegalValue; } } diff -r a775efb8fcec -r 74f47ef37394 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 Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Mon Mar 05 16:09:49 2012 -0800 @@ -28,7 +28,6 @@ import static com.oracle.max.cri.util.MemoryBarriers.*; import static com.oracle.max.graal.lir.ValueUtil.*; -import java.lang.reflect.*; import java.util.*; import com.oracle.max.asm.*; @@ -50,7 +49,11 @@ import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.lir.*; -import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.StandardOp.JumpOp; +import com.oracle.max.graal.lir.StandardOp.LabelOp; +import com.oracle.max.graal.lir.StandardOp.ParametersOp; +import com.oracle.max.graal.lir.StandardOp.PhiJumpOp; +import com.oracle.max.graal.lir.StandardOp.PhiLabelOp; import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; @@ -395,7 +398,6 @@ } if (stateAfter != null) { lastState = stateAfter; - assert checkStartOperands(instr, lastState); assert checkStateReady(lastState); if (GraalOptions.TraceLIRGeneratorLevel >= 2) { TTY.println("STATE CHANGE"); @@ -491,25 +493,6 @@ } } - private boolean checkStartOperands(Node node, FrameState fs) { - if (!Modifier.isNative(method.accessFlags())) { - if (node == ((StructuredGraph) node.graph()).start()) { - CiKind[] arguments = CiUtil.signatureToKinds(method); - int slot = 0; - for (CiKind kind : arguments) { - ValueNode arg = fs.localAt(slot); - assert arg != null && arg.kind() == kind.stackKind() : "No valid local in framestate for slot #" + slot + " (" + arg + ")"; - slot++; - if (slot < fs.localsSize() && fs.localAt(slot) == null) { - slot++; - } - } - } - } - return true; - } - - @Override public void visitArrayLength(ArrayLengthNode x) { XirArgument array = toXirArgument(x.array()); diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Mon Mar 05 16:09:49 2012 -0800 @@ -177,12 +177,6 @@ public int deoptBci; } - public static class DeoptBlock extends Block { - public DeoptBlock(int startBci) { - this.startBci = startBci; - } - } - /** * The blocks found in this method, in reverse postorder. */ @@ -320,10 +314,8 @@ case IFNULL: // fall through case IFNONNULL: { current = null; - double probability = useBranchPrediction ? profilingInfo.getBranchTakenProbability(bci) : -1; - - Block b1 = probability == 0.0 ? new DeoptBlock(bci + Bytes.beS2(code, bci + 1)) : makeBlock(bci + Bytes.beS2(code, bci + 1)); - Block b2 = probability == 1.0 ? new DeoptBlock(bci + 3) : makeBlock(bci + 3); + Block b1 = makeBlock(bci + Bytes.beS2(code, bci + 1)); + Block b2 = makeBlock(bci + 3); setSuccessors(bci, b1, b2); break; } diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/FrameStateBuilder.java Mon Mar 05 16:09:49 2012 -0800 @@ -195,6 +195,9 @@ } private void deletePhi(Node phi) { + if (phi.isDeleted()) { + return; + } // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles). List phiUsages = phi.usages().filter(NodePredicates.isA(PhiNode.class)).snapshot(); diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Mon Mar 05 16:09:49 2012 -0800 @@ -38,7 +38,6 @@ import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.java.BciBlockMapping.Block; -import com.oracle.max.graal.java.BciBlockMapping.DeoptBlock; import com.oracle.max.graal.java.BciBlockMapping.ExceptionBlock; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; @@ -536,6 +535,14 @@ private void ifNode(ValueNode x, Condition cond, ValueNode y) { assert !x.isDeleted() && !y.isDeleted(); + assert currentBlock.normalSuccessors == 2 : currentBlock.normalSuccessors; + Block trueBlock = currentBlock.successors.get(0); + Block falseBlock = currentBlock.successors.get(1); + if (trueBlock == falseBlock) { + appendGoto(createTarget(trueBlock, frameState)); + return; + } + double probability = profilingInfo.getBranchTakenProbability(bci()); if (probability < 0) { assert probability == -1 : "invalid probability"; @@ -544,15 +551,9 @@ } CompareNode condition = currentGraph.unique(new CompareNode(x, cond, y)); - FixedNode trueSuccessor = createTarget(currentBlock.successors.get(0), frameState); - FixedNode falseSuccessor = createTarget(currentBlock.successors.get(1), frameState); - if (trueSuccessor == falseSuccessor) { - appendGoto(trueSuccessor); - } else { - append(currentGraph.add(new IfNode(condition, trueSuccessor, falseSuccessor, probability))); - } - - assert currentBlock.normalSuccessors == 2 : currentBlock.normalSuccessors; + BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); + BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); + append(currentGraph.add(new IfNode(condition, trueSuccessor, falseSuccessor, probability))); } private void genIfZero(Condition cond) { @@ -1117,9 +1118,10 @@ int nofCases = ts.numberOfCases() + 1; // including default case assert currentBlock.normalSuccessors == nofCases; - TableSwitchNode tableSwitch = currentGraph.add(new TableSwitchNode(value, ts.lowKey(), switchProbability(nofCases, bci))); + double[] probabilities = switchProbability(nofCases, bci); + TableSwitchNode tableSwitch = currentGraph.add(new TableSwitchNode(value, ts.lowKey(), probabilities)); for (int i = 0; i < nofCases; ++i) { - tableSwitch.setBlockSuccessor(i, BeginNode.begin(createTarget(currentBlock.successors.get(i), frameState))); + tableSwitch.setBlockSuccessor(i, createBlockTarget(probabilities[i], currentBlock.successors.get(i), frameState)); } append(tableSwitch); } @@ -1150,9 +1152,10 @@ for (int i = 0; i < nofCases - 1; ++i) { keys[i] = ls.keyAt(i); } - LookupSwitchNode lookupSwitch = currentGraph.add(new LookupSwitchNode(value, keys, switchProbability(nofCases, bci))); + double[] probabilities = switchProbability(nofCases, bci); + LookupSwitchNode lookupSwitch = currentGraph.add(new LookupSwitchNode(value, keys, probabilities)); for (int i = 0; i < nofCases; ++i) { - lookupSwitch.setBlockSuccessor(i, BeginNode.begin(createTarget(currentBlock.successors.get(i), frameState))); + lookupSwitch.setBlockSuccessor(i, createBlockTarget(probabilities[i], currentBlock.successors.get(i), frameState)); } append(lookupSwitch); } @@ -1245,6 +1248,30 @@ return result; } + /** + * Returns a block begin node with the specified state. If the specified probability is 0, the block + * deoptimizes immediately. + */ + private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) { + assert probability >= 0 && probability <= 1; + if (probability == 0) { + FrameStateBuilder state = stateAfter.copy(); + state.clearNonLiveLocals(block.localsLiveIn); + + BeginNode begin = currentGraph.add(new BeginNode()); + DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + begin.setNext(deopt); + begin.setStateAfter(state.create(block.startBci)); + return begin; + } + + FixedNode target = createTarget(block, stateAfter); + assert !(target instanceof BeginNode); + BeginNode begin = currentGraph.add(new BeginNode()); + begin.setNext(target); + return begin; + } + private ValueNode synchronizedObject(FrameStateBuilder state, RiResolvedMethod target) { if (isStatic(target.accessFlags())) { return append(ConstantNode.forCiConstant(target.holder().getEncoding(Representation.JavaClass), runtime, currentGraph)); @@ -1282,8 +1309,6 @@ createUnwind(); } else if (block instanceof ExceptionBlock) { createExceptionDispatch((ExceptionBlock) block); - } else if (block instanceof DeoptBlock) { - createDeopt(); } else { frameState.setRethrowException(false); iterateBytecodesForBlock(block); @@ -1327,10 +1352,6 @@ } } - private void createDeopt() { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile))); - } - private void createUnwind() { synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI); UnwindNode unwindNode = currentGraph.add(new UnwindNode(frameState.apop())); diff -r a775efb8fcec -r 74f47ef37394 graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Mon Mar 05 16:09:07 2012 -0800 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Mon Mar 05 16:09:49 2012 -0800 @@ -50,6 +50,14 @@ @Override public void dump(Object object, String message) { + try { + dumpSandboxed(object, message); + } catch (Throwable ex) { + TTY.println("CFGPrinter: Exception during output of " + message + ": " + ex); + } + } + + public void dumpSandboxed(Object object, String message) { GraalCompiler compiler = Debug.contextLookup(GraalCompiler.class); if (compiler == null) { return;