# HG changeset patch # User Thomas Wuerthinger # Date 1309537444 -7200 # Node ID 5cdaa94cd622ebde4392a717348a4eb8bc23e6ef # Parent 0affee9ff3a9923a3a70cebb5f817e6db4954ecd# Parent 3664989976e2aee48278b4928a43893e3df714a9 Merge. diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Fri Jul 01 18:24:04 2011 +0200 @@ -72,7 +72,7 @@ Graph.verificationListeners.add(new VerificationListener() { @Override public void verificationFailed(Node n, String message) { - GraalCompiler.this.fireCompilationEvent(new CompilationEvent(currentCompilation, "Verification Error on Node " + n.id(), currentCompilation.graph, true, false)); + GraalCompiler.this.fireCompilationEvent(new CompilationEvent(currentCompilation, "Verification Error on Node " + n.id(), currentCompilation.graph, true, false, true)); TTY.println(n.toString()); for (Node p : n.predecessors()) { TTY.println("predecessor: " + p); @@ -146,7 +146,7 @@ if (GraalOptions.PrintDOTGraphToPdf) { addCompilationObserver(new GraphvizPrinterObserver(true)); } - if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot) { + if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) { CompilationObserver observer; if (GraalOptions.PrintIdealGraphFile) { observer = new IdealGraphPrinterObserver(); diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Fri Jul 01 18:24:04 2011 +0200 @@ -54,6 +54,11 @@ public static int MaximumDesiredSize = 8000; public static int MaximumShortLoopSize = 5; + // escape analysis settings + public static boolean EscapeAnalysis = ____; + public static int ForcedInlineEscapeWeight = 0; + public static int MaximumEscapeAnalysisArrayLength = 32; + // debugging settings public static boolean VerifyPointerMaps = ____; public static int MethodEndBreakpointGuards = 0; @@ -80,6 +85,7 @@ // Ideal graph visualizer output settings public static boolean Plot = ____; + public static boolean PlotOnError = ____; public static int PrintIdealGraphLevel = 0; public static boolean PrintIdealGraphFile = ____; public static String PrintIdealGraphAddress = "127.0.0.1"; @@ -101,6 +107,7 @@ public static boolean TraceAssembler = ____; public static boolean TraceInlining = ____; public static boolean TraceDeadCodeElimination = ____; + public static boolean TraceEscapeAnalysis = ____; public static boolean TraceCanonicalizer = ____; public static boolean TraceMemoryMaps = ____; public static boolean TraceReadElimination = ____; diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Fri Jul 01 18:24:04 2011 +0200 @@ -36,6 +36,7 @@ import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.lir.LIRInstruction.*; import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.compiler.value.FrameState.*; @@ -318,7 +319,7 @@ LIRInstruction instructionForId(int opId) { assert isEven(opId) : "opId not even"; LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; - assert instr.id == opId; + assert instr.id() == opId; return instr; } @@ -460,7 +461,7 @@ // iterate all instructions of the block. skip the first because it is always a label for (int j = 1; j < numInst; j++) { LIRInstruction op = instructions.get(j); - int opId = op.id; + int opId = op.id(); if (opId == -1) { CiValue resultOperand = op.result(); @@ -568,7 +569,7 @@ int numInst = instructions.size(); for (int j = 0; j < numInst; j++) { LIRInstruction op = instructions.get(j); - op.id = opId; + op.setId(opId); opIdToInstructionMap[index] = op; opIdToBlockMap[index] = block; @@ -616,7 +617,7 @@ if (!liveKill.get(operandNum)) { liveGen.set(operandNum); if (GraalOptions.TraceLinearScanLevel >= 4) { - TTY.println(" Setting liveGen for operand %d at instruction %d", operandNum, op.id); + TTY.println(" Setting liveGen for operand %d at instruction %d", operandNum, op.id()); } } if (block.loopIndex() >= 0) { @@ -641,7 +642,7 @@ if (!liveKill.get(operandNum)) { liveGen.set(operandNum); if (GraalOptions.TraceLinearScanLevel >= 4) { - TTY.println(" Setting liveGen for value %s, LIR opId %d, operand %d because of state for " + op.toString(), Util.valueString(value), op.id, operandNum); + TTY.println(" Setting liveGen for value %s, LIR opId %d, operand %d because of state for " + op.toString(), Util.valueString(value), op.id(), operandNum); } } } else if (operand.isRegister()) { @@ -848,13 +849,13 @@ if (block.liveGen.get(operandNum)) { TTY.println(" used in block B%d", block.blockID()); for (LIRInstruction ins : block.lir().instructionsList()) { - TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); + TTY.println(ins.id() + ": " + ins.result() + " " + ins.toString()); } } if (block.liveKill.get(operandNum)) { TTY.println(" defined in block B%d", block.blockID()); for (LIRInstruction ins : block.lir().instructionsList()) { - TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); + TTY.println(ins.id() + ": " + ins.result() + " " + ins.toString()); } } } @@ -1102,8 +1103,8 @@ if (GraalOptions.DetailedAsserts) { int argSlots = compilation.method.signature().argumentSlots(!isStatic(compilation.method.accessFlags())); assert slot.index() >= 0 && slot.index() < argSlots; - assert move.id > 0 : "invalid id"; - assert blockForId(move.id).numberOfPreds() == 0 : "move from stack must be in first block"; + assert move.id() > 0 : "invalid id"; + assert blockForId(move.id()).numberOfPreds() == 0 : "move from stack must be in first block"; assert move.result().isVariable() : "result of move must be a variable"; if (GraalOptions.TraceLinearScanLevel >= 4) { @@ -1137,7 +1138,7 @@ if (from != null && to != null) { to.setLocationHint(from); if (GraalOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation at opId %d: added hint from interval %d to %d", move.id, from.operandNumber, to.operandNumber); + TTY.println("operation at opId %d: added hint from interval %d to %d", move.id(), from.operandNumber, to.operandNumber); } } } @@ -1155,7 +1156,7 @@ if (from != null && to != null) { to.setLocationHint(from); if (GraalOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id, from.operandNumber, to.operandNumber); + TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id(), from.operandNumber, to.operandNumber); } } } @@ -1179,8 +1180,8 @@ final int blockFrom = block.firstLirInstructionId(); int blockTo = block.lastLirInstructionId(); - assert blockFrom == instructions.get(0).id; - assert blockTo == instructions.get(instructions.size() - 1).id; + assert blockFrom == instructions.get(0).id(); + assert blockTo == instructions.get(instructions.size() - 1).id(); // Update intervals for operands live at the end of this block; BitMap live = block.liveOut; @@ -1208,7 +1209,7 @@ assert !instructions.get(0).hasOperands() : "first operation must always be a label"; for (int j = instructions.size() - 1; j >= 1; j--) { LIRInstruction op = instructions.get(j); - final int opId = op.id; + final int opId = op.id(); // add a temp range for each register if operation destroys caller-save registers if (op.hasCall) { @@ -1269,9 +1270,17 @@ if (info != null) { info.state.forEachLiveStateValue(new ValueProcedure() { public void doValue(Value value) { - CiValue operand = value.operand(); - if (operand.isVariableOrRegister()) { - addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null); + if (value instanceof VirtualObject) { + VirtualObject obj = (VirtualObject) value; + do { + doValue(obj.input()); + obj = obj.object(); + } while (obj != null); + } else { + CiValue operand = value.operand(); + if (operand.isVariableOrRegister()) { + addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null); + } } } }); @@ -1315,7 +1324,7 @@ if (GraalOptions.TraceLinearScanLevel >= 2) { TTY.println("killing XMMs for trig"); } - int opId = op.id; + int opId = op.id(); for (CiRegister r : compilation.registerConfig.getCallerSaveRegisters()) { if (r.isFpu()) { @@ -1770,19 +1779,19 @@ void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, boolean isCallSite, BitMap frameRefMap, BitMap regRefMap) { if (GraalOptions.TraceLinearScanLevel >= 3) { - TTY.println("creating oop map at opId %d", op.id); + TTY.println("creating oop map at opId %d", op.id()); } // walk before the current operation . intervals that start at // the operation (i.e. output operands of the operation) are not // included in the oop map - iw.walkBefore(op.id); + iw.walkBefore(op.id()); // Iterate through active intervals for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { CiValue operand = interval.operand; - assert interval.currentFrom() <= op.id && op.id <= interval.currentTo() : "interval should not be active otherwise"; + assert interval.currentFrom() <= op.id() && op.id() <= interval.currentTo() : "interval should not be active otherwise"; assert interval.operand.isVariable() : "fixed interval found"; // Check if this range covers the instruction. Intervals that @@ -1791,7 +1800,7 @@ // moves, any intervals which end at this instruction are included // in the oop map since we may safepoint while doing the patch // before we've consumed the inputs. - if (op.id < interval.currentTo()) { + if (op.id() < interval.currentTo()) { // caller-save registers must not be included into oop-maps at calls assert !isCallSite || !operand.isRegister() || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; @@ -1803,7 +1812,7 @@ // Spill optimization: when the stack value is guaranteed to be always correct, // then it must be added to the oop map even if the interval is currently in a register - if (interval.alwaysInMemory() && op.id > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) { + if (interval.alwaysInMemory() && op.id() > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) { assert interval.spillDefinitionPos() > 0 : "position not set correctly"; assert interval.spillSlot() != null : "no spill slot assigned"; assert !interval.operand.isRegister() : "interval is on stack : so stack slot is registered twice"; @@ -1837,7 +1846,9 @@ } CiValue toCiValue(int opId, Value value) { - if (value != null && value.operand() != CiValue.IllegalValue) { + 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) { @@ -1884,6 +1895,35 @@ } } + private CiVirtualObject toCiVirtualObject(int opId, VirtualObject obj) { + RiType type = obj.type(); + EscapeField[] escapeFields = obj.fields(); + CiValue[] values = new CiValue[escapeFields.length]; + + 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()); + } + found = true; + break; + } + } + assert found : type + "." + current.field() + " not found"; + current = current.object(); + } while (current != null); + + for (int i = 0; i < escapeFields.length; i++) { + assert values[i] != null : type + "." + escapeFields[i]; + } + + CiVirtualObject vobj = CiVirtualObject.get(type, values, obj.id()); + return vobj; + } + CiFrame computeFrameForState(FrameState state, int opId, BitMap frameRefMap) { CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; int valueIndex = 0; @@ -1937,11 +1977,11 @@ int frameWords = frameSize / compilation.target.spillSlotSize; BitMap frameRefMap = new BitMap(frameWords); BitMap regRefMap = !op.hasCall ? new BitMap(compilation.target.arch.registerReferenceMapBitCount) : null; - CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id, frameRefMap); + CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id(), frameRefMap); computeOopMap(iw, op, info, frameRefMap, regRefMap); info.debugInfo = new CiDebugInfo(frame, regRefMap, frameRefMap); } else if (GraalOptions.DetailedAsserts) { - assert info.debugInfo.frame().equals(computeFrame(info.state, op.id, new BitMap(info.debugInfo.frameRefMap.size()))); + assert info.debugInfo.frame().equals(computeFrame(info.state, op.id(), new BitMap(info.debugInfo.frameRefMap.size()))); } } } @@ -1970,7 +2010,7 @@ for (int k = 0; k < n; k++) { CiValue operand = op.operandAt(mode, k); if (operand.isVariable()) { - op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id, mode)); + op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id(), mode)); } } } @@ -2256,14 +2296,14 @@ LIRInstruction op = instructions.get(j); if (op.info != null) { - iw.walkBefore(op.id); + iw.walkBefore(op.id()); boolean checkLive = true; // Make sure none of the fixed registers is live across an // oopmap since we can't handle that correctly. if (checkLive) { for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { - if (interval.currentTo() > op.id + 1) { + if (interval.currentTo() > op.id() + 1) { // This interval is live out of this op so make sure // that this interval represents some value that's // referenced by this op either as an input or output. diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Fri Jul 01 18:24:04 2011 +0200 @@ -233,15 +233,15 @@ // When the block already contains spill moves, the index must be increased until the // correct index is reached. List list = opBlock.lir().instructionsList(); - int index = (opId - list.get(0).id) >> 1; - assert list.get(index).id <= opId : "error in calculation"; + int index = (opId - list.get(0).id()) >> 1; + assert list.get(index).id() <= opId : "error in calculation"; - while (list.get(index).id != opId) { + while (list.get(index).id() != opId) { index++; assert 0 <= index && index < list.size() : "index out of bounds"; } assert 1 <= index && index < list.size() : "index out of bounds"; - assert list.get(index).id == opId : "error in calculation"; + assert list.get(index).id() == opId : "error in calculation"; // insert new instruction before instruction at position index moveResolver.moveInsertPosition(opBlock.lir(), index - 1); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Fri Jul 01 18:24:04 2011 +0200 @@ -229,8 +229,8 @@ CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, j); if (allocator.isProcessed(operand)) { Interval interval = intervalAt(operand); - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Input, allocator); + if (op.id() != -1) { + interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Input, allocator); } assert checkState(inputState, interval.location(), interval.splitParent()); @@ -251,8 +251,8 @@ if (allocator.isProcessed(operand)) { Interval interval = intervalAt(operand); assert interval != null : "Could not find interval for operand " + operand; - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Temp, allocator); + if (op.id() != -1) { + interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Temp, allocator); } statePut(inputState, interval.location(), interval.splitParent()); @@ -265,8 +265,8 @@ CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, j); if (allocator.isProcessed(operand)) { Interval interval = intervalAt(operand); - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Output, allocator); + if (op.id() != -1) { + interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Output, allocator); } statePut(inputState, interval.location(), interval.splitParent()); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java Fri Jul 01 18:24:04 2011 +0200 @@ -479,7 +479,7 @@ out.println("LIR"); for (int i = 0; i < lir.length(); i++) { LIRInstruction inst = lir.at(i); - out.printf("nr %4d ", inst.id).print(COLUMN_END); + out.printf("nr %4d ", inst.id()).print(COLUMN_END); if (inst.info != null) { int level = out.indentationLevel(); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java Fri Jul 01 18:24:04 2011 +0200 @@ -24,6 +24,7 @@ import java.io.*; import java.util.*; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Map.Entry; import com.oracle.max.graal.compiler.ir.*; @@ -109,24 +110,33 @@ flush(); } + public void print(Graph graph, String title, boolean shortNames) { + print(graph, title, shortNames, Collections.emptyMap()); + } + /** * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes. */ - public void print(Graph graph, String title, boolean shortNames) { + public void print(Graph graph, String title, boolean shortNames, Map debugObjects) { stream.printf(" %n", escape(title)); noBlockNodes.clear(); IdentifyBlocksPhase schedule = null; try { schedule = new IdentifyBlocksPhase(true); - schedule.apply(graph); + schedule.apply(graph, false); } catch (Throwable t) { // nothing to do here... + //t.printStackTrace(); + } + List loops = null; + try { + loops = LoopUtil.computeLoops(graph); + } catch (Throwable t) { t.printStackTrace(); } - List loops = LoopUtil.computeLoops(graph); stream.println(" "); - List edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops); + List edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops, debugObjects); stream.println(" "); stream.println(" "); @@ -148,11 +158,52 @@ flush(); } - private List printNodes(Graph graph, boolean shortNames, NodeMap nodeToBlock, List loops) { + private List printNodes(Graph graph, boolean shortNames, NodeMap nodeToBlock, List loops, Map debugObjects) { ArrayList edges = new ArrayList(); NodeBitMap loopExits = graph.createNodeBitMap(); - for (Loop loop : loops) { - loopExits.markAll(loop.exist()); + if (loops != null) { + for (Loop loop : loops) { + loopExits.setUnion(loop.exits()); + } + } + + Map>> colors = new HashMap>>(); + Map> bits = new HashMap>(); + if (debugObjects != null) { + for (Entry entry : debugObjects.entrySet()) { + String name = entry.getKey(); + Object obj = entry.getValue(); + if (obj instanceof NodeMap) { + Map colorNumbers = new HashMap(); + int nextColor = 0; + NodeMap map = (NodeMap) obj; + for (Entry mapEntry : map.entries()) { + Node node = mapEntry.getKey(); + Object color = mapEntry.getValue(); + Integer colorNumber = colorNumbers.get(color); + if (colorNumber == null) { + colorNumber = nextColor++; + colorNumbers.put(color, colorNumber); + } + Set> nodeColors = colors.get(node); + if (nodeColors == null) { + nodeColors = new HashSet>(); + colors.put(node, nodeColors); + } + nodeColors.add(new SimpleImmutableEntry(name + "Color", colorNumber)); + } + } else if (obj instanceof NodeBitMap) { + NodeBitMap bitmap = (NodeBitMap) obj; + for (Node node : bitmap) { + Set nodeBits = bits.get(node); + if (nodeBits == null) { + nodeBits = new HashSet(); + bits.put(node, nodeBits); + } + nodeBits.add(name); + } + } + } } for (Node node : graph.getNodes()) { @@ -188,17 +239,35 @@ stream.printf("

true

%n"); } StringBuilder sb = new StringBuilder(); - for (Loop loop : loops) { - if (loop.nodes().isMarked(node)) { - if (sb.length() > 0) { - sb.append(", "); + if (loops != null) { + for (Loop loop : loops) { + if (loop.nodes().isMarked(node)) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(loop.loopBegin().id()); } - sb.append(loop.loopBegin().id()); } } if (sb.length() > 0) { stream.printf("

%s

%n", sb); } + + Set> nodeColors = colors.get(node); + if (nodeColors != null) { + for (Entry color : nodeColors) { + String name = color.getKey(); + Integer value = color.getValue(); + stream.printf("

%d

%n", name, value); + } + } + Set nodeBits = bits.get(node); + if (nodeBits != null) { + for (String bit : nodeBits) { + stream.printf("

true

%n", bit); + } + } + for (Entry entry : props.entrySet()) { String key = entry.getKey().toString(); String value = entry.getValue() == null ? "null" : entry.getValue().toString(); @@ -237,11 +306,9 @@ stream.printf(" %n", block.blockID()); stream.printf(" %n"); for (Block sux : block.getSuccessors()) { -// if (sux.firstNode() instanceof LoopBegin && block.lastNode() instanceof LoopEnd) { //TODO gd -// // Skip back edges. -// } else { + if (sux != null) { stream.printf(" %n", sux.blockID()); -// } + } } stream.printf(" %n"); stream.printf(" %n"); diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java Fri Jul 01 18:24:04 2011 +0200 @@ -67,7 +67,7 @@ public void compilationStarted(CompilationEvent event) { assert (stream == null && printer == null); - if (!TTY.isSuppressed()) { + if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && event.isErrorEvent())) { String name = event.getMethod().holder().name(); name = name.substring(1, name.length() - 1).replace('/', '.'); name = name + "." + event.getMethod().name(); @@ -140,9 +140,17 @@ @Override public void compilationEvent(CompilationEvent event) { + boolean lazyStart = false; + if (printer == null && event.isErrorEvent()) { + this.compilationStarted(event); + lazyStart = true; + } if (printer != null && event.getGraph() != null && event.isHIRValid()) { Graph graph = event.getGraph(); - printer.print(graph, event.getLabel(), true); + printer.print(graph, event.getLabel(), true, event.getDebugObjects()); + } + if (lazyStart) { + this.compilationFinished(event); } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Fri Jul 01 18:24:04 2011 +0200 @@ -395,7 +395,7 @@ @Override public void visitNewObjectArray(NewObjectArray x) { XirArgument length = toXirArgument(x.length()); - XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType()); + XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementType(), x.exactType()); emitXir(snippet, x, stateFor(x), null, true); } @@ -1074,7 +1074,7 @@ lastState = fs; } else if (block.blockPredecessors().size() == 1) { FrameState fs = block.blockPredecessors().get(0).lastState(); - assert fs != null; //TODO gd maybe this assert should be removed + assert fs != null; if (GraalOptions.TraceLIRGeneratorLevel >= 2) { TTY.println("STATE CHANGE (singlePred)"); if (GraalOptions.TraceLIRGeneratorLevel >= 3) { @@ -1485,6 +1485,9 @@ } private void moveToPhi(Merge merge, Node pred) { + if (GraalOptions.TraceLIRGeneratorLevel >= 1) { + TTY.println("MOVE TO PHI from " + pred + " to " + merge); + } int nextSuccIndex = merge.phiPredecessorIndex(pred); PhiResolver resolver = new PhiResolver(this); for (Phi phi : merge.phis()) { @@ -1628,7 +1631,9 @@ private void walkStateValue(Value value) { if (value != null) { - if (value instanceof Phi && !((Phi) value).isDead()) { + 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()) { @@ -1639,6 +1644,13 @@ } } + private void walkVirtualObject(VirtualObject value) { + walkStateValue(value.input()); + if (value.object() != null) { + walkVirtualObject(value.object()); + } + } + protected LIRDebugInfo stateFor(Value x) { assert lastState != null : "must have state before instruction for " + x; return stateFor(x, lastState); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Fri Jul 01 18:24:04 2011 +0200 @@ -90,7 +90,7 @@ //printGraph("After DeadCodeElimination", compilation.graph); if (GraalOptions.Inline) { - new InliningPhase(compilation, this, GraalOptions.TraceInlining).apply(compilation.graph); + new InliningPhase(compilation, this, null).apply(compilation.graph); } Graph graph = compilation.graph; @@ -100,6 +100,13 @@ new DeadCodeEliminationPhase().apply(graph); } + if (GraalOptions.EscapeAnalysis) { + new EscapeAnalysisPhase(compilation, this).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + } + if (GraalOptions.OptGVN) { new GlobalValueNumberingPhase().apply(graph); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/EndNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/EndNode.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/EndNode.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,6 +22,8 @@ */ 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.*; @@ -67,4 +69,9 @@ assertTrue(predecessors().size() <= 1, "at most one predecessor"); return true; } + + @Override + public Iterable< ? extends Node> dataUsages() { + return Collections.emptyList(); + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java Fri Jul 01 18:24:04 2011 +0200 @@ -29,9 +29,10 @@ /** * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler. */ -public final class ExceptionObject extends FixedNodeWithNext { +public final class ExceptionObject extends StateSplit { private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; /** diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Fri Jul 01 18:24:04 2011 +0200 @@ -84,7 +84,6 @@ public final RiMethod target; public final RiType returnType; public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL - public final RiTypeProfile profile; /** * Constructs a new Invoke instruction. @@ -95,13 +94,12 @@ * @param isStatic {@code true} if this call is static (no receiver object) * @param target the target method being called */ - public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, RiTypeProfile profile, Graph graph) { + public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) { super(result, args.length, SUCCESSOR_COUNT, graph); this.opcode = opcode; this.target = target; this.returnType = returnType; this.bci = bci; - this.profile = profile; this.argumentCount = args.length; for (int i = 0; i < args.length; i++) { @@ -148,10 +146,6 @@ return target; } - public RiTypeProfile profile() { - return profile; - } - /** * Checks whether this invocation has a receiver object. * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a @@ -201,7 +195,7 @@ @Override public Node copy(Graph into) { - Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, profile, into); + Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into); return x; } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java Fri Jul 01 18:24:04 2011 +0200 @@ -28,10 +28,9 @@ import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; -public class LoopBegin extends Merge{ +public class LoopBegin extends Merge { public LoopBegin(Graph graph) { super(graph); - this.addEnd(new EndNode(graph)); } public LoopEnd loopEnd() { @@ -81,6 +80,16 @@ throw Util.shouldNotReachHere("unknown pred : " + pred + "(sp=" + forwardEdge() + ", le=" + this.loopEnd() + ")"); } + @Override + public Node phiPredecessorAt(int index) { + if (index == 0) { + return forwardEdge(); + } else if (index == 1) { + return loopEnd(); + } + throw Util.shouldNotReachHere(); + } + public Collection counters() { return Util.filter(this.usages(), LoopCounter.class); } @@ -107,6 +116,12 @@ } @Override + public Node singlePredecessor() { + assert endCount() == 1; + return endAt(0).singlePredecessor(); + } + + @Override public Iterable< ? extends Node> dataUsages() { final Iterator< ? extends Node> dataUsages = super.dataUsages().iterator(); return new Iterable() { diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java Fri Jul 01 18:24:04 2011 +0200 @@ -337,6 +337,10 @@ return endIndex(end); } + public Node phiPredecessorAt(int index) { + return endAt(index); + } + public Collection phis() { return Util.filter(this.usages(), Phi.class); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,6 +22,12 @@ */ package com.oracle.max.graal.compiler.ir; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp; +import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -30,6 +36,8 @@ */ 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; @@ -67,4 +75,154 @@ super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); setLength(length); } + + /** + * The list of instructions which produce input for this instruction. + */ + public Value dimension(int index) { + assert index == 0; + return length(); + } + + /** + * The rank of the array allocated by this instruction, i.e. how many array dimensions. + */ + public int dimensionCount() { + return 1; + } + + public abstract CiKind elementKind(); + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == EscapeOp.class) { + return (T) ESCAPE; + } + return super.lookup(clazz); + } + + private static class NewArrayEscapeOp implements EscapeOp { + + @Override + public boolean canAnalyze(Node node) { + NewArray x = (NewArray) node; + CiConstant length = x.dimension(0).asConstant(); + return length != null && length.asInt() >= 0 && length.asInt() < GraalOptions.MaximumEscapeAnalysisArrayLength; + } + + @Override + public boolean escape(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + assert x.object() == node; + return false; + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.object() == node; + return false; + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + assert x.inputs().contains(node); + return true; + } else if (usage instanceof LoadIndexed) { + LoadIndexed x = (LoadIndexed) usage; + assert x.array() == node; + CiConstant index = x.index().asConstant(); + CiConstant length = ((NewArray) node).dimension(0).asConstant(); + if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) { + return true; + } + return false; + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + assert x.value() == node; + return true; + } else if (usage instanceof StoreIndexed) { + StoreIndexed x = (StoreIndexed) usage; + CiConstant index = x.index().asConstant(); + CiConstant length = ((NewArray) node).dimension(0).asConstant(); + if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) { + return true; + } + return x.value() == node; + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + assert x.object() == node; + return false; + } else if (usage instanceof ArrayLength) { + ArrayLength x = (ArrayLength) usage; + assert x.array() == node; + return false; + } else if (usage instanceof VirtualObject) { + return false; + } else { + return true; + } + } + + @Override + public EscapeField[] fields(Node node) { + NewArray x = (NewArray) node; + int length = x.dimension(0).asConstant().asInt(); + EscapeField[] fields = new EscapeField[length]; + for (int i = 0; i < length; i++) { + Integer representation = i; + fields[i] = new EscapeField("[" + i + "]", representation, ((NewArray) node).elementKind()); + } + return fields; + } + + @Override + public void beforeUpdate(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replaceAndDelete(guard.next()); + } + x.delete(); + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.type() == ((NewArray) node).exactType(); + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replaceAndDelete(guard.next()); + } + x.delete(); + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + x.replaceAndDelete(x.next()); + } else if (usage instanceof ArrayLength) { + ArrayLength x = (ArrayLength) usage; + x.replaceAndDelete(((NewArray) node).dimension(0)); + } + } + + @Override + public void updateState(Node node, Node current, Map fields, Map 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) { + for (Node usage : new ArrayList(x.usages())) { + assert fieldState.get(field) != null; + usage.inputs().replace(x, fieldState.get(field)); + } + 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()); + assert x.usages().size() == 0; + x.replaceAndDelete(x.next()); + } + } + } + } + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,12 @@ */ package com.oracle.max.graal.compiler.ir; +import java.util.*; + import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp; +import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -30,7 +35,8 @@ /** * The {@code NewInstance} instruction represents the allocation of an instance class object. */ -public final class NewInstance extends FloatingNode { +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; @@ -85,4 +91,124 @@ NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into); return x; } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == EscapeOp.class) { + return (T) ESCAPE; + } + return super.lookup(clazz); + } + + private static class NewInstanceEscapeOp implements EscapeOp { + + @Override + public boolean canAnalyze(Node node) { + return ((NewInstance) node).instanceClass().isResolved(); + } + + @Override + public boolean escape(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + assert x.object() == node; + return false; + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.object() == node; + return false; + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + assert x.inputs().contains(node); + return true; + } else if (usage instanceof LoadField) { + LoadField x = (LoadField) usage; + assert x.object() == node; + return x.field().isResolved() == false; + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + return x.value() == node; + } else if (usage instanceof StoreIndexed) { + StoreIndexed x = (StoreIndexed) usage; + assert x.value() == node; + return true; + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + assert x.object() == node; + return false; + } else if (usage instanceof VirtualObject) { + return false; + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + assert x.object() == node; + return false; + } else { + return true; + } + } + + @Override + public EscapeField[] fields(Node node) { + NewInstance x = (NewInstance) node; + RiField[] riFields = x.instanceClass().fields(); + EscapeField[] fields = new EscapeField[riFields.length]; + for (int i = 0; i < riFields.length; i++) { + RiField field = riFields[i]; + fields[i] = new EscapeField(field.name(), field, field.kind().stackKind()); + } + return fields; + } + + @Override + public void beforeUpdate(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replaceAndDelete(guard.next()); + } + x.delete(); + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.type() == ((NewInstance) node).instanceClass(); + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replaceAndDelete(guard.next()); + } + x.delete(); + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + x.replaceAndDelete(x.next()); + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + x.replaceAndDelete(x.next()); + } + } + + @Override + public void updateState(Node node, Node current, Map fields, Map 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(); + for (Node usage : new ArrayList(x.usages())) { + usage.inputs().replace(x, fieldState.get(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()); + assert x.usages().size() == 0; + x.replaceAndDelete(x.next()); + } + } + } + } + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Fri Jul 01 18:24:04 2011 +0200 @@ -50,6 +50,7 @@ /** * The list of instructions which produce input for this instruction. */ + @Override public Value dimension(int index) { assert index >= 0 && index < dimensionCount; return (Value) inputs().get(super.inputCount() + index); @@ -63,6 +64,7 @@ /** * The rank of the array allocated by this instruction, i.e. how many array dimensions. */ + @Override public int dimensionCount() { return dimensionCount; } @@ -105,6 +107,21 @@ } @Override + public CiKind elementKind() { + return elementType.kind(); + } + + @Override + public RiType exactType() { + return elementType.arrayOf(); + } + + @Override + public RiType declaredType() { + return exactType(); + } + + @Override public void print(LogStream out) { out.print("new multi array ["); for (int i = 0; i < dimensionCount; i++) { diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Fri Jul 01 18:24:04 2011 +0200 @@ -52,11 +52,16 @@ * Gets the type of the elements of the array. * @return the element type of the array */ - public RiType elementClass() { + public RiType elementType() { return elementClass; } @Override + public CiKind elementKind() { + return elementClass.kind(); + } + + @Override public RiType exactType() { return elementClass.arrayOf(); } @@ -73,7 +78,7 @@ @Override public void print(LogStream out) { - out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass())); + out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementType())); } @Override diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Fri Jul 01 18:24:04 2011 +0200 @@ -42,6 +42,7 @@ this.elementType = elementType; } + @Override public CiKind elementKind() { return elementType.kind(); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java Fri Jul 01 18:24:04 2011 +0200 @@ -22,7 +22,10 @@ */ package com.oracle.max.graal.compiler.ir; +import java.util.*; + import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.StateSplit.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -59,6 +62,7 @@ } public void setMerge(Merge n) { + assert n != null; inputs().set(super.inputCount() + INPUT_MERGE, n); } @@ -139,7 +143,11 @@ } str.append(valueAt(i) == null ? "-" : valueAt(i).id()); } - return "Phi: (" + str + ")"; + if (isDead()) { + return "Phi: dead (" + str + ")"; + } else { + return "Phi: (" + str + ")"; + } } public void addInput(Node y) { @@ -156,4 +164,16 @@ x.isDead = isDead; return x; } + + @Override + public Iterable dataInputs() { + final Iterator< ? extends Node> input = super.dataInputs().iterator(); + return new Iterable() { + @Override + public Iterator iterator() { + // TODO Auto-generated method stub + return new FilteringIterator(input, Merge.class); + } + }; + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java Fri Jul 01 18:24:04 2011 +0200 @@ -26,7 +26,6 @@ import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -179,7 +178,7 @@ return properties; } - @Override + /*@Override public Iterable dataUsages() { final Iterator dataUsages = super.dataUsages().iterator(); return new Iterable() { @@ -188,5 +187,5 @@ return new StateSplit.FilteringIterator(dataUsages, FrameState.class); } }; - } + }*/ } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.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/VirtualObject.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,132 @@ +/* + * 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.compiler.phases.EscapeAnalysisPhase.EscapeField; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +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 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 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) { + 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() { + return type; + } + + public EscapeField[] fields() { + return fields; + } + + @Override + public void accept(ValueVisitor v) { + // nothing to do... + } + + @Override + 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(); + } + + @Override + public void print(LogStream out) { + out.print(object()).print(".").print(field.name()).print("=").print(input()); + } + + @Override + public Node copy(Graph into) { + VirtualObject x = new VirtualObject(null, null, field, type, fields, into); + return x; + } +} diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/WriteNode.java diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Fri Jul 01 18:24:04 2011 +0200 @@ -90,7 +90,7 @@ /** * Value id for register allocation. */ - public int id; + private int id; /** * Determines if all caller-saved registers are destroyed by this instruction. @@ -198,6 +198,14 @@ assert verifyOperands(); } + public final int id() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + private LIROperand initOutput(CiValue output) { assert output != null; if (output != CiValue.IllegalValue) { diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java Fri Jul 01 18:24:04 2011 +0200 @@ -52,6 +52,8 @@ private CiTargetMethod targetMethod; private boolean hirValid = false; private boolean lirValid = false; + private boolean errorEvent; + private Map debugObjects; private Interval[] intervals; private int intervalsSize; @@ -68,10 +70,23 @@ } public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid) { + this(compilation, label, graph, hirValid, lirValid, false, (Map) null); + } + public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, boolean error) { + this(compilation, label, graph, hirValid, lirValid, error, (Map) null); + } + + public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, Map debugObjects) { + this(compilation, label, graph, hirValid, lirValid, false, debugObjects); + } + + public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, boolean error, Map debugObjects) { this(compilation, label); this.graph = graph; this.hirValid = hirValid; this.lirValid = lirValid; + this.debugObjects = debugObjects; + this.errorEvent = error; } public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, CiTargetMethod targetMethod) { @@ -128,6 +143,10 @@ return lirValid; } + public boolean isErrorEvent() { + return errorEvent; + } + public Interval[] getIntervals() { if (intervalsCopy == null && intervals != null) { // deferred copy of the valid range of the intervals array @@ -139,4 +158,9 @@ public int getCodeSize() { return codeSize; } + + + public Map getDebugObjects() { + return debugObjects; + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,387 @@ +/* + * 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.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.schedule.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +public class EscapeAnalysisPhase extends Phase { + + + public static class BlockExitState { + public final Map fieldState; + public VirtualObject obj; + + public BlockExitState() { + this.fieldState = new HashMap(); + } + } + + public class EscapementFixup { + + private List blocks; + private final Map fields = new HashMap(); + private final Map exitStates = new HashMap(); + + private final EscapeOp op; + private Graph graph; + private final Node node; + private RiType type; + private EscapeField[] escapeFields; + + public EscapementFixup(EscapeOp op, Graph graph, Node node) { + this.op = op; + this.graph = graph; + this.node = node; + } + + public void apply() { + process(); + removeAllocation(); + } + + public void removeAllocation() { + final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true); + identifyBlocksPhase.apply(graph); + blocks = identifyBlocksPhase.getBlocks(); + + 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); + } + + 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) { + state.obj = null; + 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 { + 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) { + 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)); + } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) { + mergedFields.add(field); + } + } + } + } + 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); + } + } + } + + Node current; + if (block.firstNode() instanceof StartNode) { + current = ((StartNode) block.firstNode()).start(); + } else { + current = block.firstNode(); + } + while (current != block.lastNode()) { + Node next = ((FixedNodeWithNext) current).next(); + op.updateState(node, current, fields, state.fieldState); + if (!current.isDeleted() && current instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) current).stateAfter(); + if (stateAfter != null) { + updateFrameState(stateAfter, state.obj); + } + } + current = next; + } + + 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); + } + }, startBlock); + + 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; + } + } + if (simple != null) { + for (Node usage : new ArrayList(phi.usages())) { + usage.inputs().replace(phi, simple); + } + phi.delete(); + } 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); + } + } + } + } + // the rest of the usages should be dead frame states... + for (Node usage : new ArrayList(node.usages())) { + assert usage instanceof FrameState || usage instanceof VirtualObject; + usage.inputs().replace(node, Node.Null); + } + + if (node instanceof FixedNodeWithNext) { + node.replaceAndDelete(((FixedNodeWithNext) node).next()); + } else { + node.delete(); + } + } + + private VirtualObject 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 { + current = updateVirtualObject(obj, current); + obj = obj.object(); + } while (obj != null); + } + } + if (frameState.outerFrameState() != null) { + current = updateFrameState(frameState.outerFrameState(), current); + } + return current; + } + + private VirtualObject updateVirtualObject(VirtualObject obj, VirtualObject current) { + if (obj.input() == node) { + obj.setInput(current); + } else if (obj.input() instanceof VirtualObject) { + VirtualObject obj2 = (VirtualObject) obj.input(); + do { + current = updateVirtualObject(obj2, current); + obj2 = obj2.object(); + } while (obj2 != null); + } + return current; + } + + private void process() { + for (Node usage : new ArrayList(node.usages())) { + op.beforeUpdate(node, usage); + } + } + } + + private final GraalCompilation compilation; + private final IR ir; + + public EscapeAnalysisPhase(GraalCompilation compilation, IR ir) { + this.compilation = compilation; + this.ir = ir; + } + + @Override + protected void run(Graph graph) { +// if (!compilation.method.holder().name().contains("jnt")) { +// return; +// } +// if (true) return; + for (Node node : graph.getNodes()) { + EscapeOp op = node.lookup(EscapeOp.class); + if (op != null && op.canAnalyze(node)) { + Set exits = new HashSet(); + Set invokes = new HashSet(); + int iterations = 0; + + int weight; + int minimumWeight = GraalOptions.ForcedInlineEscapeWeight; + do { + weight = analyze(op, node, exits, invokes); + if (exits.size() != 0) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("####### escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method); + TTY.print("%d: new value: %d %s, weight %d, escapes at ", iterations, node.id(), node.shortName(), weight); + for (Node n : exits) { + TTY.print("%d %s, ", n.id(), n.shortName()); + } + for (Node n : invokes) { + TTY.print("%d %s, ", n.id(), n.shortName()); + } + TTY.println(); + } + break; + } + if (invokes.size() == 0) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method); + } + new EscapementFixup(op, graph, node).apply(); + new PhiSimplifier(graph); + break; + } + if (weight < minimumWeight) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method); + } + break; + } + new InliningPhase(compilation, ir, invokes).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + exits.clear(); + invokes.clear(); + } while (iterations++ < 3); + } + } + } + + private int analyze(EscapeOp op, Node node, Collection exits, Collection invokes) { + int weight = 0; + for (Node usage : node.usages()) { + boolean escapes = op.escape(node, usage); + if (escapes) { + if (usage instanceof FrameState) { + // nothing to do... + } else if (usage instanceof Invoke) { + invokes.add((Invoke) usage); + } else { + exits.add(usage); + if (!GraalOptions.TraceEscapeAnalysis) { + break; + } + } + } else { + weight++; + } + } + return weight; + } + + public static class EscapeField { + + private String name; + private Object representation; + private CiKind kind; + + public EscapeField(String name, Object representation, CiKind kind) { + this.name = name; + this.representation = representation; + this.kind = kind; + } + + public String name() { + return name; + } + + public Object representation() { + return representation; + } + + public CiKind kind() { + return kind; + } + + @Override + public String toString() { + return name(); + } + } + + public static interface EscapeOp extends Op { + + boolean canAnalyze(Node node); + + boolean escape(Node node, Node usage); + + EscapeField[] fields(Node node); + + void beforeUpdate(Node node, Node usage); + + void updateState(Node node, Node current, Map fields, Map fieldState); + + } +} diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -201,7 +201,7 @@ List loops = LoopUtil.computeLoops(graph); NodeBitMap loopExits = graph.createNodeBitMap(); for (Loop loop : loops) { - loopExits.markAll(loop.exist()); + loopExits.setUnion(loop.exits()); } // remove Placeholders @@ -325,12 +325,12 @@ Merge merge = new Merge(graph); assert p.predecessors().size() == 1 : "predecessors size: " + p.predecessors().size(); FixedNode next = p.next(); - p.setNext(null); EndNode end = new EndNode(graph); - p.replaceAndDelete(end); + p.setNext(end); merge.setNext(next); merge.addEnd(end); merge.setStateAfter(existingState); + p.setStateAfter(existingState.duplicate(bci)); if (!(next instanceof LoopEnd)) { target.firstInstruction = merge; } @@ -436,12 +436,17 @@ p.setStateAfter(frameState.duplicateWithoutStack(bci)); Value currentExceptionObject; + ExceptionObject newObj = null; if (exceptionObject == null) { - currentExceptionObject = new ExceptionObject(graph); + newObj = new ExceptionObject(graph); + currentExceptionObject = newObj; } else { currentExceptionObject = exceptionObject; } FrameState stateWithException = frameState.duplicateWithException(bci, currentExceptionObject); + if (newObj != null) { + newObj.setStateAfter(stateWithException); + } FixedNode target = createTarget(dispatchBlock, stateWithException); if (exceptionObject == null) { ExceptionObject eObj = (ExceptionObject) currentExceptionObject; @@ -964,7 +969,7 @@ append(deoptimize); frameState.pushReturn(resultType, Constant.defaultForKind(resultType, graph)); } else { - Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), method.typeProfile(bci()), graph); + Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph); Value result = appendWithBCI(invoke); invoke.setExceptionEdge(handleException(null, bci())); frameState.pushReturn(resultType, result); @@ -1201,6 +1206,7 @@ if (block.firstInstruction == null) { if (block.isLoopHeader) { LoopBegin loopBegin = new LoopBegin(graph); + loopBegin.addEnd(new EndNode(graph)); LoopEnd loopEnd = new LoopEnd(graph); loopEnd.setLoopBegin(loopBegin); Placeholder pBegin = new Placeholder(graph); @@ -1231,7 +1237,14 @@ } else { EndNode end = new EndNode(graph); ((Merge) result).addEnd(end); - result = end; + Placeholder p = new Placeholder(graph); + int bci = block.startBci; + if (block instanceof ExceptionBlock) { + bci = ((ExceptionBlock) block).deoptBci; + } + p.setStateAfter(stateAfter.duplicate(bci)); + p.setNext(end); + result = p; } } assert !(result instanceof LoopBegin || result instanceof Merge); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -32,118 +32,84 @@ import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction; import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; public class InliningPhase extends Phase { + public static final HashMap methodCount = new HashMap(); + private final GraalCompilation compilation; private final IR ir; - private final Queue invokes = new ArrayDeque(); - private final Queue methods = new ArrayDeque(); + private int inliningSize; + private final Collection hints; - private final Map parentMethod = new HashMap(); - private int inliningSize; - private final boolean trace; - - public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) { + public InliningPhase(GraalCompilation compilation, IR ir, Collection hints) { this.compilation = compilation; this.ir = ir; - this.trace = trace; + this.hints = hints; } - private void addToQueue(Invoke invoke, RiMethod method) { - invokes.add(invoke); - methods.add(method); - inliningSize += method.codeSize(); - } + private Queue newInvokes = new ArrayDeque(); + private Graph graph; - public static HashMap methodCount = new HashMap(); @Override protected void run(Graph graph) { + this.graph = graph; + float ratio = GraalOptions.MaximumInlineRatio; inliningSize = compilation.method.codeSize(); - for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { + + if (hints != null) { + newInvokes.addAll(hints); + } else { for (Invoke invoke : graph.getNodes(Invoke.class)) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } - RiTypeProfile profile = parent.typeProfile(invoke.bci); - if (!checkInvokeConditions(invoke)) { - continue; - } - if (invoke.target.canBeStaticallyBound()) { - if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) { - addToQueue(invoke, invoke.target); - } - } else { - RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); - if (concrete != null) { - if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { - if (trace) { - String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false); - String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false); - TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName); - } - compilation.assumptions.recordConcreteMethod(invoke.target, concrete); - addToQueue(invoke, concrete); + newInvokes.add(invoke); + } + } + + for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { + Queue queue = newInvokes; + newInvokes = new ArrayDeque(); + for (Invoke invoke : queue) { + if (!invoke.isDeleted()) { + RiMethod code = inlineInvoke(invoke, iterations, ratio); + if (code != null) { + inliningSize += code.codeSize(); + if (inliningSize > GraalOptions.MaximumInstructionCount) { + break; } - } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { - if (GraalOptions.InlineWithTypeCheck) { - // type check and inlining... - concrete = profile.types[0].resolveMethodImpl(invoke.target); - if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { - IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph); - FixedGuard guard = new FixedGuard(isType, graph); - assert invoke.predecessors().size() == 1; - invoke.predecessors().get(0).successors().replace(invoke, guard); - guard.setNext(invoke); - if (trace) { - TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]); - } - addToQueue(invoke, concrete); + inlineMethod(invoke, code); + if (GraalOptions.TraceInlining) { + if (methodCount.get(code) == null) { + methodCount.put(code, 1); + } else { + methodCount.put(code, methodCount.get(code) + 1); } } } } - if (inliningSize > GraalOptions.MaximumInstructionCount) { - break; - } } - - assert invokes.size() == methods.size(); - if (invokes.isEmpty()) { - break; - } - - Invoke invoke; - while ((invoke = invokes.poll()) != null) { - RiMethod method = methods.remove(); - inlineMethod(invoke, method); - - if (methodCount.get(method) == null) { - methodCount.put(method, 1); - } else { - methodCount.put(method, methodCount.get(method) + 1); - } - } - DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase(); - dce.apply(graph); - if (inliningSize > GraalOptions.MaximumInstructionCount) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("inlining stopped: MaximumInstructionCount reached"); } break; } + if (newInvokes.isEmpty()) { + break; + } + +// new DeadCodeEliminationPhase().apply(graph); + ratio *= GraalOptions.MaximumInlineRatio; } - if (trace) { + if (GraalOptions.TraceInlining) { int inlined = 0; int duplicate = 0; for (Map.Entry entry : methodCount.entrySet()) { @@ -156,16 +122,90 @@ } } + private RiMethod inlineInvoke(Invoke invoke, int iterations, float ratio) { + RiMethod parent = invoke.stateAfter().method(); + RiTypeProfile profile = parent.typeProfile(invoke.bci); + if (!checkInvokeConditions(invoke)) { + return null; + } + if (invoke.opcode() == Bytecodes.INVOKESPECIAL || invoke.target.canBeStaticallyBound()) { + if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) { + return invoke.target; + } + return null; + } + if (invoke.receiver().exactType() != null) { + RiType exact = invoke.receiver().exactType(); + assert exact.isSubtypeOf(invoke.target().holder()) : exact + " subtype of " + invoke.target().holder(); + RiMethod resolved = exact.resolveMethodImpl(invoke.target()); + if (checkTargetConditions(resolved, iterations) && checkSizeConditions(resolved, invoke, profile, ratio)) { + return resolved; + } + return null; + } + RiType holder = invoke.target().holder(); + + if (invoke.receiver().declaredType() != null) { + RiType declared = invoke.receiver().declaredType(); + // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...) + // TODO (ls) fix this + if (declared.isResolved() && declared.isSubtypeOf(invoke.target().holder())) { + holder = declared; + } + } + + RiMethod concrete = holder.uniqueConcreteMethod(invoke.target); + if (concrete != null) { + if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { + if (GraalOptions.TraceInlining) { + String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false); + String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false); + TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + return concrete; + } + return null; + } + if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { + if (GraalOptions.InlineWithTypeCheck) { + // type check and inlining... + concrete = profile.types[0].resolveMethodImpl(invoke.target); + if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { + IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph); + FixedGuard guard = new FixedGuard(graph); + guard.setNode(isType); + assert invoke.predecessors().size() == 1; + invoke.predecessors().get(0).successors().replace(invoke, guard); + guard.setNext(invoke); + + if (GraalOptions.TraceInlining) { + TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]); + } + return concrete; + } + return null; + } else { + if (GraalOptions.TraceInlining) { + TTY.println("not inlining %s because GraalOptions.InlineWithTypeCheck == false", methodName(invoke.target, invoke)); + } + return null; + } + } else { + if (GraalOptions.TraceInlining) { + TTY.println("not inlining %s because no monomorphic receiver could be found", methodName(invoke.target, invoke)); + } + return null; + } + } + private String methodName(RiMethod method) { return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; } private String methodName(RiMethod method, Invoke invoke) { if (invoke != null) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } + RiMethod parent = invoke.stateAfter().method(); return parent.name() + "@" + invoke.bci + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; } else { return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; @@ -174,31 +214,31 @@ private boolean checkInvokeConditions(Invoke invoke) { if (invoke.stateAfter() == null) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because the invoke has no after state", methodName(invoke.target, invoke)); } return false; } if (invoke.stateAfter().locksSize() > 0) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of locks", methodName(invoke.target, invoke)); } return false; } if (!invoke.target.isResolved()) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because the invoke target is unresolved", methodName(invoke.target, invoke)); } return false; } if (invoke.predecessors().size() == 0) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because the invoke is dead code", methodName(invoke.target, invoke)); } return false; } if (invoke.stateAfter() == null) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of missing frame state", methodName(invoke.target, invoke)); } } @@ -207,31 +247,31 @@ private boolean checkTargetConditions(RiMethod method, int iterations) { if (!method.isResolved()) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because it is unresolved", methodName(method)); } return false; } if (Modifier.isNative(method.accessFlags())) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because it is a native method", methodName(method)); } return false; } if (Modifier.isAbstract(method.accessFlags())) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because it is an abstract method", methodName(method)); } return false; } if (!method.holder().isInitialized()) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of non-initialized class", methodName(method)); } return false; } if (method == compilation.method && iterations > GraalOptions.MaximumRecursiveInlineLevel) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of recursive inlining limit", methodName(method)); } return false; @@ -240,8 +280,12 @@ } private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) { - if (method.codeSize() > GraalOptions.MaximumInlineSize) { - if (trace) { + int maximumSize = GraalOptions.MaximumInlineSize; + if (hints != null && hints.contains(invoke)) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } + if (method.codeSize() > maximumSize) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize); } return false; @@ -253,10 +297,7 @@ int maximumSize = GraalOptions.MaximumTrivialSize; float ratio = 0; if (profile != null && profile.count > 0) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } + RiMethod parent = invoke.stateAfter().method(); ratio = profile.count / (float) parent.invocationCount(); if (ratio >= GraalOptions.FreqInlineRatio) { maximumSize = GraalOptions.MaximumFreqInlineSize; @@ -264,13 +305,16 @@ maximumSize = GraalOptions.MaximumInlineSize; } } + if (hints != null && hints.contains(invoke)) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } if (method.codeSize() > maximumSize) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile); } return false; } - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("inlining %s (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile); } return true; @@ -286,12 +330,12 @@ CompilerGraph graph; Object stored = GraphBuilderPhase.cachedGraphs.get(method); if (stored != null) { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("Reusing graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize()); } graph = (CompilerGraph) stored; } else { - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("Building graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize()); } graph = new CompilerGraph(null); @@ -337,7 +381,7 @@ } } - if (trace) { + if (GraalOptions.TraceInlining) { TTY.println("inlining %s: %d frame states, %d nodes", methodName(method), frameStates.size(), nodes.size()); } @@ -345,7 +389,8 @@ assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); FixedNodeWithNext pred; if (withReceiver) { - FixedGuard clipNode = new FixedGuard(new IsNonNull(parameters[0], compilation.graph), compilation.graph); + FixedGuard clipNode = new FixedGuard(compilation.graph); + clipNode.setNode(new IsNonNull(parameters[0], compilation.graph)); pred = clipNode; } else { pred = new Placeholder(compilation.graph); @@ -357,7 +402,7 @@ for (Node node : duplicates.values()) { if (node instanceof Invoke) { - parentMethod.put((Invoke) node, method); + newInvokes.add((Invoke) node); } } @@ -425,7 +470,7 @@ } } - if (trace) { + if (GraalOptions.TraceInlining) { ir.printGraph("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false), compilation.graph); } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -26,6 +26,7 @@ import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.util.LoopUtil.Loop; import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; @@ -35,14 +36,22 @@ @Override protected void run(Graph graph) { - for (LoopBegin n : graph.getNodes(LoopBegin.class)) { - doLoop(n); + List loops = LoopUtil.computeLoops(graph); + +// for (Loop loop : loops) { +// System.out.println("Peel loop : " + loop.loopBegin()); +// LoopUtil.peelLoop(loop); +// } +// loops = LoopUtil.computeLoops(graph); // TODO (gd) avoid recomputing loops + + for (Loop loop : loops) { + doLoopCounters(loop); } } - private void doLoop(LoopBegin loopBegin) { - NodeBitMap loopNodes = LoopUtil.computeLoopNodes(loopBegin); - List counters = findLoopCounters(loopBegin, loopNodes); + private void doLoopCounters(Loop loop) { + LoopBegin loopBegin = loop.loopBegin(); + List counters = findLoopCounters(loopBegin, loop.nodes()); mergeLoopCounters(counters, loopBegin); } @@ -102,6 +111,9 @@ if (phi.valueCount() == 2) { Value backEdge = phi.valueAt(1); Value init = phi.valueAt(0); + if (loopNodes.isNew(init) || loopNodes.isNew(backEdge)) { + continue; + } if (loopNodes.isMarked(init)) { // try to reverse init/backEdge order Value tmp = backEdge; @@ -127,7 +139,7 @@ useCounterAfterAdd = true; } } - if (stride != null && !loopNodes.isMarked(stride)) { + if (stride != null && !loopNodes.isNew(stride) && !loopNodes.isMarked(stride)) { Graph graph = loopBegin.graph(); LoopCounter counter = new LoopCounter(init.kind, init, stride, loopBegin, graph); counters.add(counter); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java Fri Jul 01 18:24:04 2011 +0200 @@ -48,6 +48,10 @@ } public final void apply(Graph graph) { + apply(graph, true); + } + + public final void apply(Graph graph, boolean plotOnError) { assert graph != null && (!shouldVerify || graph.verify()); int startDeletedNodeCount = graph.getDeletedNodeCount(); @@ -62,7 +66,21 @@ GraalTimers.get(getName()).start(); } //System.out.println("Starting Phase " + getName()); - run(graph); + try { + run(graph); + } catch (AssertionError t) { + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved() && plotOnError) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "AssertionError in " + getName(), graph, true, false, true)); + } + throw t; + } catch (RuntimeException t) { + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved() && plotOnError) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "RuntimeException in " + getName(), graph, true, false, true)); + } + throw t; + } //System.out.println("Finished Phase " + getName()); if (GraalOptions.Time) { GraalTimers.get(getName()).stop(); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Fri Jul 01 18:24:04 2011 +0200 @@ -182,4 +182,46 @@ public void setInstructions(List instructions) { this.instructions = instructions; } + + public static void iteratePostOrder(List blocks, BlockClosure closure) { + ArrayList startBlocks = new ArrayList(); + for (Block block : blocks) { + if (block.getPredecessors().size() == 0) { + startBlocks.add(block); + } + } + iteratePostOrder(blocks, closure, startBlocks.toArray(new Block[startBlocks.size()])); + } + + public static void iteratePostOrder(List blocks, BlockClosure closure, Block... startBlocks) { + BitMap visited = new BitMap(blocks.size()); + LinkedList workList = new LinkedList(); + for (Block block : startBlocks) { + workList.add(block); + visited.set(block.blockID()); + } + + while (!workList.isEmpty()) { + Block b = workList.remove(); + + closure.apply(b); + + for (Block succ : b.getSuccessors()) { + if (!visited.get(succ.blockID())) { + boolean delay = false; + for (Block pred : succ.getPredecessors()) { + if (!visited.get(pred.blockID()) && !(pred.lastNode instanceof LoopEnd)) { + delay = true; + break; + } + } + + if (!delay) { + visited.set(succ.blockID()); + workList.add(succ); + } + } + } + } + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java Fri Jul 01 18:24:04 2011 +0200 @@ -125,6 +125,7 @@ break; } currentNode = currentNode.singlePredecessor(); + assert !currentNode.isDeleted(); } } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,333 @@ +/* + * 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.util; + +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.graph.NodeWorkList.*; + +public class GraphUtil { + + public static interface ColoringLambda { + T color(Iterable incomming, Merge merge); + T danglingColor(Iterable incomming, Merge merge); + } + + /** + * colors down, applying the lambda at merge points, starting at the pre-colored points. + */ + public static void colorCFGDown(NodeMap colors, ColoringLambda lambda) { + Set delayed = new HashSet(); + Set currentPoints = new HashSet(); + Set otherPoints = new HashSet(); + Set otherMerges = new HashSet(); + for (Entry entry : colors.entries()) { + currentPoints.add(entry.getKey()); + } + ArrayList incomming = new ArrayList(2); + while (!currentPoints.isEmpty()) { + for (Node node : currentPoints) { + otherMerges.addAll(colorCFGDownToMerge(node, colors.get(node), colors)); + } + for (Merge merge : otherMerges) { + incomming.clear(); + for (EndNode end : merge.cfgPredecessors()) { + incomming.add(colors.get(end)); + } + T color = lambda.color(incomming, merge); + if (color != null) { + colors.set(merge, color); + colors.set(merge.next(), color); + otherPoints.add(merge.next()); + delayed.remove(merge); + } else { + delayed.add(merge); + } + } + Set tmp = currentPoints; + currentPoints = otherPoints; + otherPoints = tmp; + otherPoints.clear(); + otherMerges.clear(); + } + for (Merge merge : delayed) { + T color = lambda.danglingColor(incomming, merge); + if (color != null) { + colors.set(merge, color); + } + } + + + /*List startingPoints = new LinkedList(); + for (Entry entry : colors.entries()) { + startingPoints.add(entry.getKey()); + } + NodeWorkList work = colors.graph().createNodeWorkList(); + for (Node startingPoint : startingPoints) { + if (startingPoint instanceof Merge) { + work.addAll(colorCFGDownToMerge(((Merge) startingPoint).next(), colors.get(startingPoint), colors)); + } else { + work.addAll(colorCFGDownToMerge(startingPoint, colors.get(startingPoint), colors)); + } + } + for (Node n : work) { + //System.out.println("Color : work on " + n); + Merge merge = (Merge) n; + ArrayList incomming = new ArrayList(2); + for (EndNode end : merge.cfgPredecessors()) { + incomming.add(colors.get(end)); + } + T color = lambda.color(incomming, merge); + if (color != null) { + colors.set(merge, color); + work.addAll(colorCFGDownToMerge(merge.next(), color, colors)); + } else { + System.out.println("Can not color " + merge); + work.addAgain(merge); + } + }*/ + } + + private static Collection colorCFGDownToMerge(Node from, T color, NodeMap colors) { + //System.out.println("colorCFGDownToMerge(" + from + ", " + color + ", colors)"); + NodeFlood work = from.graph().createNodeFlood(); + Collection merges = new LinkedList(); + work.add(from); + for (Node node : work) { + //System.out.println("colorToMerge : work on " + node); + Node current = node; + while (current != null) { + //System.out.println("colorToMerge : current " + current); + if (current instanceof Merge) { + merges.add((Merge) current); + break; + } + colors.set(current, color); + if (current instanceof FixedNodeWithNext) { + current = ((FixedNodeWithNext) current).next(); + } else if (current instanceof EndNode) { + current = ((EndNode) current).merge(); + } else { + if (current instanceof ControlSplit) { + for (Node sux : current.cfgSuccessors()) { + work.add(sux); + } + } + current = null; + } + } + } + //System.out.println("return " + merges); + return merges; + } + + public static interface ColorSplitingLambda { + void fixSplit(Node oldNode, Node newNode, T color); + void fixNode(Node node, T color); + Value fixPhiInput(Value input, T color); + boolean explore(Node n); + } + + // TODO (gd) rework that code around Phi handling : too complicated + public static void splitFromColoring(NodeMap coloring, ColorSplitingLambda lambda) { + Map internalColoring = new HashMap(); + NodeWorkList work = coloring.graph().createNodeWorkList(); + for (Entry entry : coloring.entries()) { + T color = entry.getValue(); + Node node = entry.getKey(); + work.add(node); + internalColoring.put(node, color); + } + Set colors = new HashSet(); + try { + for (Node node : work) { + //System.out.println("Split : work on " + node); + if (node instanceof Phi) { + Phi phi = (Phi) node; + Merge merge = phi.merge(); + for (int i = 0; i < phi.valueCount(); i++) { + Value v = phi.valueAt(i); + if (v != null) { + T color = internalColoring.get(merge.phiPredecessorAt(i)); + if (color != null) { + Value replace = lambda.fixPhiInput(v, color); + if (replace != v) { + phi.setValueAt(i, replace); + } else { + if (lambda.explore(v) && coloring.get(v) == null && !work.isNew(v)) { + //System.out.println("Split : Add input " + input + " to work from " + node); + work.add(v); + } + } + } + } + } + } else { + boolean delay = false; + colors.clear(); + T originalColoringColor = coloring.get(node); + if (originalColoringColor == null && internalColoring.get(node) != null) { + //System.out.println("Split : ori == null && intern != null -> continue"); + continue; + } + if (originalColoringColor == null) { + for (Node usage : node.dataUsages()) { + if (usage instanceof Phi) { + Phi phi = (Phi) usage; + Merge merge = phi.merge(); + //System.out.println("Split merge : " + merge + ".endCount = " + merge.endCount() + " phi " + phi + ".valueCount : " + phi.valueCount()); + for (int i = 0; i < phi.valueCount(); i++) { + Value v = phi.valueAt(i); + if (v == node) { + T color = internalColoring.get(merge.phiPredecessorAt(i)); + if (color != null) { + colors.add(color); + } + } + } + } else { + T color = internalColoring.get(usage); + if (color == null) { + //System.out.println("Split : color from " + usage + " is null"); + delay = true; + break; + } + colors.add(color); + } + } + if (delay) { + //System.out.println("Split : delay"); + work.addAgain(node); + continue; + } + } else { + colors.add(originalColoringColor); + } + if (colors.size() == 1) { + //System.out.println("Split : 1 color, coloring, fixing"); + T color = colors.iterator().next(); + internalColoring.put(node, color); + lambda.fixNode(node, color); + } else { + //System.out.println("Split : " + colors.size() + " colors, coloring, spliting, fixing"); + for (T color : colors) { + Node newNode = node.copy(); + for (int i = 0; i < node.inputs().size(); i++) { + Node input = node.inputs().get(i); + newNode.inputs().setOrExpand(i, input); + } + for (int i = 0; i < node.successors().size(); i++) { + Node input = node.successors().get(i); + newNode.successors().setOrExpand(i, input); + } + internalColoring.put(newNode, color); + lambda.fixSplit(node, newNode, color); + LinkedList dataUsages = new LinkedList(); + for (Node usage : node.dataUsages()) { + dataUsages.add(usage); + } + for (Node usage : dataUsages) { + if (usage instanceof Phi) { + Phi phi = (Phi) usage; + Merge merge = phi.merge(); + for (int i = 0; i < phi.valueCount(); i++) { + Value v = phi.valueAt(i); + if (v == node) { + T uColor = internalColoring.get(merge.endAt(i)); + if (uColor == color) { + phi.setValueAt(i, (Value) newNode); + } + } + } + } else { + T uColor = internalColoring.get(usage); + if (uColor == color) { + usage.inputs().replace(node, newNode); + } + } + } + } + } + if (node instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) node).stateAfter(); + if (stateAfter != null && lambda.explore(stateAfter) && !work.isNew(stateAfter)) { + //System.out.println("Split : Add framestate to work"); + work.add(stateAfter); + } + } + + if (node instanceof Merge) { + for (Node usage : node.usages()) { + if (!work.isNew(usage)) { + work.add(usage); + } + } + } + + if (node instanceof LoopEnd) { + work.add(((LoopEnd) node).loopBegin()); + } + + for (Node input : node.dataInputs()) { + if (lambda.explore(input) && coloring.get(input) == null && !work.isNew(input)) { + //System.out.println("Split : Add input " + input + " to work from " + node); + work.add(input); + } + } + } + } + } catch (InfiniteWorkException re) { + System.out.println("Infinite work, current queue :"); + for (Node n : work) { + System.out.println(" - " + n); + } + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + NodeMap debugColoring = coloring.graph().createNodeMap(); + for (Entry entry : internalColoring.entrySet()) { + debugColoring.set(entry.getKey(), entry.getValue()); + } + Map debug = new HashMap(); + debug.put("split", debugColoring); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "RuntimeException in split", coloring.graph(), true, false, true, debug)); + } + throw re; + } + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + NodeMap debugColoring = coloring.graph().createNodeMap(); + for (Entry entry : internalColoring.entrySet()) { + debugColoring.set(entry.getKey(), entry.getValue()); + } + Map debug = new HashMap(); + debug.put("split", debugColoring); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Split end!!", coloring.graph(), true, false, debug)); + } + } +} diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java Fri Jul 01 18:24:04 2011 +0200 @@ -23,22 +23,29 @@ package com.oracle.max.graal.compiler.util; import java.util.*; +import java.util.Map.Entry; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.GraphUtil.ColorSplitingLambda; +import com.oracle.max.graal.compiler.util.GraphUtil.ColoringLambda; +import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; public class LoopUtil { public static class Loop { private final LoopBegin loopBegin; - private final NodeBitMap nodes; + private NodeBitMap nodes; private Loop parent; - private final List exits; - public Loop(LoopBegin loopBegin, NodeBitMap nodes) { + private NodeBitMap exits; + public Loop(LoopBegin loopBegin, NodeBitMap nodes, NodeBitMap exits) { this.loopBegin = loopBegin; this.nodes = nodes; - this.exits = new LinkedList(); + this.exits = exits; } public LoopBegin loopBegin() { @@ -53,38 +60,42 @@ return parent; } - public List exist() { + public NodeBitMap exits() { return exits; } public void setParent(Loop parent) { this.parent = parent; } + + public boolean isChild(Loop loop) { + return loop.parent != null && (loop.parent == this || loop.parent.isChild(this)); + } + } + + private static class PeelingResult { + public final FixedNode begin; + public final FixedNode end; + public final NodeMap exits; + public final NodeMap phis; + public final NodeMap phiInits; + public final NodeMap dataOut; + public PeelingResult(FixedNode begin, FixedNode end, NodeMap exits, NodeMap phis, NodeMap phiInits, NodeMap dataOut) { + this.begin = begin; + this.end = end; + this.exits = exits; + this.phis = phis; + this.phiInits = phiInits; + this.dataOut = dataOut; + } } public static List computeLoops(Graph graph) { List loops = new LinkedList(); for (LoopBegin loopBegin : graph.getNodes(LoopBegin.class)) { NodeBitMap nodes = computeLoopNodes(loopBegin); - Loop loop = new Loop(loopBegin, nodes); - NodeFlood workCFG = graph.createNodeFlood(); - workCFG.add(loopBegin.loopEnd()); - for (Node n : workCFG) { - if (n == loopBegin) { - continue; - } - if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) { - for (Node sux : n.cfgSuccessors()) { - if (!nodes.isMarked(sux) && sux instanceof FixedNode) { - loop.exits.add((FixedNode) sux); - } - } - } - for (Node pred : n.cfgPredecessors()) { - workCFG.add(pred); - } - } - loops.add(loop); + NodeBitMap exits = computeLoopExits(loopBegin, nodes); + loops.add(new Loop(loopBegin, nodes, exits)); } for (Loop loop : loops) { for (Loop other : loops) { @@ -98,20 +109,117 @@ return loops; } - public static NodeBitMap computeLoopNodes(LoopBegin loopBegin) { - LoopEnd loopEnd = loopBegin.loopEnd(); - NodeBitMap loopNodes = loopBegin.graph().createNodeBitMap(); - NodeFlood workCFG = loopBegin.graph().createNodeFlood(); - NodeFlood workData1 = loopBegin.graph().createNodeFlood(); - NodeFlood workData2 = loopBegin.graph().createNodeFlood(); - workCFG.add(loopEnd); + public static NodeBitMap computeLoopExits(LoopBegin loopBegin, NodeBitMap nodes) { + Graph graph = loopBegin.graph(); + NodeBitMap exits = graph.createNodeBitMap(); + NodeFlood workCFG = graph.createNodeFlood(); + workCFG.add(loopBegin.loopEnd()); for (Node n : workCFG) { - workData1.add(n); - workData2.add(n); - loopNodes.mark(n); if (n == loopBegin) { continue; } + if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) { + for (Node sux : n.cfgSuccessors()) { + if (!nodes.isMarked(sux) && sux instanceof FixedNode) { + exits.mark(sux); + } + } + } + for (Node pred : n.cfgPredecessors()) { + workCFG.add(pred); + } + } + return exits; + } + + public static NodeBitMap computeLoopNodes(LoopBegin loopBegin) { + return computeLoopNodesFrom(loopBegin, loopBegin.loopEnd()); + } + private static boolean recurse = false; + public static NodeBitMap computeLoopNodesFrom(LoopBegin loopBegin, FixedNode from) { + NodeFlood workData1 = loopBegin.graph().createNodeFlood(); + NodeFlood workData2 = loopBegin.graph().createNodeFlood(); + NodeBitMap loopNodes = markUpCFG(loopBegin, from); + loopNodes.mark(loopBegin); + for (Node n : loopNodes) { + workData1.add(n); + workData2.add(n); + } + NodeBitMap inOrAfter = loopBegin.graph().createNodeBitMap(); + for (Node n : workData1) { + markWithState(n, inOrAfter); + for (Node usage : n.dataUsages()) { + if (usage instanceof Phi) { // filter out data graph cycles + Phi phi = (Phi) usage; + if (!phi.isDead()) { + Merge merge = phi.merge(); + if (merge instanceof LoopBegin) { + LoopBegin phiLoop = (LoopBegin) merge; + int backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd()); + if (phi.valueAt(backIndex) == n) { + continue; + } + } + } + } + workData1.add(usage); + } + } + NodeBitMap inOrBefore = loopBegin.graph().createNodeBitMap(); + for (Node n : workData2) { + markWithState(n, inOrBefore); + if (n instanceof Phi) { // filter out data graph cycles + Phi phi = (Phi) n; + if (!phi.isDead()) { + int backIndex = -1; + Merge merge = phi.merge(); + if (!loopNodes.isMarked(merge) && merge instanceof LoopBegin) { + LoopBegin phiLoop = (LoopBegin) merge; + backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd()); + } + for (int i = 0; i < phi.valueCount(); i++) { + if (i != backIndex) { + workData2.add(phi.valueAt(i)); + } + } + } + } else { + for (Node input : n.dataInputs()) { + workData2.add(input); + } + } + if (n instanceof Merge) { //add phis & counters + for (Node usage : n.dataUsages()) { + workData2.add(usage); + } + } + } + if (!recurse) { + recurse = true; + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + Map debug = new HashMap(); + debug.put("loopNodes", loopNodes); + debug.put("inOrAfter", inOrAfter); + debug.put("inOrBefore", inOrBefore); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Compute loop nodes loop#" + loopBegin.id(), loopBegin.graph(), true, false, debug)); + } + recurse = false; + } + inOrAfter.setIntersect(inOrBefore); + loopNodes.setUnion(inOrAfter); + return loopNodes; + } + + private static NodeBitMap markUpCFG(LoopBegin loopBegin, FixedNode from) { + NodeFlood workCFG = loopBegin.graph().createNodeFlood(); + workCFG.add(from); + NodeBitMap loopNodes = loopBegin.graph().createNodeBitMap(); + for (Node n : workCFG) { + if (n == loopBegin) { + continue; + } + loopNodes.mark(n); if (n instanceof LoopBegin) { workCFG.add(((LoopBegin) n).loopEnd()); } @@ -119,27 +227,478 @@ workCFG.add(pred); } } - NodeBitMap inOrAfter = loopBegin.graph().createNodeBitMap(); - for (Node n : workData1) { - inOrAfter.mark(n); - for (Node usage : n.dataUsages()) { - workData1.add(usage); + return loopNodes; + } + + public static void ifDoWhileTransform(Loop loop, If split) { + assert loop.nodes().isMarked(split); + FixedNode noExit = split.trueSuccessor(); + FixedNode exit = split.falseSuccessor(); + if (loop.nodes().isMarked(exit) && !loop.nodes().isMarked(noExit)) { + FixedNode tmp = noExit; + noExit = exit; + exit = tmp; + } + assert !loop.nodes().isMarked(exit); + assert loop.nodes().isMarked(noExit); + + PeelingResult peeling = preparePeeling(loop, split); + rewirePeeling(peeling, loop, split); + // TODO (gd) move peeled part to the end, rewire dataOut + } + + public static void peelLoop(Loop loop) { + LoopEnd loopEnd = loop.loopBegin().loopEnd(); + PeelingResult peeling = preparePeeling(loop, loopEnd); + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After peeling preparation", loopEnd.graph(), true, false)); + } + /*System.out.println("Peeling : "); + System.out.println(" begin = " + peeling.begin); + System.out.println(" end = " + peeling.end); + System.out.println(" Phis :"); + for (Entry entry : peeling.phis.entries()) { + System.out.println(" - " + entry.getKey() + " -> " + entry.getValue()); + } + System.out.println(" Exits :"); + for (Entry entry : peeling.exits.entries()) { + System.out.println(" - " + entry.getKey() + " -> " + entry.getValue()); + } + System.out.println(" PhiInits :"); + for (Entry entry : peeling.phiInits.entries()) { + System.out.println(" - " + entry.getKey() + " -> " + entry.getValue()); + } + System.out.println(" DataOut :"); + for (Entry entry : peeling.dataOut.entries()) { + System.out.println(" - " + entry.getKey() + " -> " + entry.getValue()); + }*/ + rewirePeeling(peeling, loop, loopEnd); + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After rewirePeeling", loopEnd.graph(), true, false)); + } + // update parents + Loop parent = loop.parent(); + while (parent != null) { + parent.nodes = computeLoopNodes(loop.loopBegin); + parent.exits = computeLoopExits(parent.loopBegin, parent.nodes); + parent = parent.parent; + } + } + + private static void rewirePeeling(PeelingResult peeling, Loop loop, FixedNode from) { + LoopBegin loopBegin = loop.loopBegin(); + Graph graph = loopBegin.graph(); + Node loopPred = loopBegin.singlePredecessor(); + loopPred.successors().replace(loopBegin.forwardEdge(), peeling.begin); + NodeBitMap loopNodes = loop.nodes(); + Node originalLast = from; + if (originalLast == loopBegin.loopEnd()) { + originalLast = loopBegin.loopEnd().singlePredecessor(); + } + int size = originalLast.successors().size(); + boolean found = false; + for (int i = 0; i < size; i++) { + Node sux = originalLast.successors().get(i); + if (sux == null) { + continue; + } + if (loopNodes.isMarked(sux)) { + assert !found; + peeling.end.successors().set(i, loopBegin.forwardEdge()); + found = true; } } - NodeBitMap inOrBefore = loopBegin.graph().createNodeBitMap(); - for (Node n : workData2) { - inOrBefore.mark(n); - for (Node input : n.dataInputs()) { - workData2.add(input); + assert found; + int phiInitIndex = loopBegin.phiPredecessorIndex(loopBegin.forwardEdge()); + for (Entry entry : peeling.phis.entries()) { + Phi phi = (Phi) entry.getKey(); + Placeholder p = entry.getValue(); + p.replaceAndDelete(phi.valueAt(phiInitIndex)); + } + for (Entry entry : peeling.phiInits.entries()) { + Phi phi = (Phi) entry.getKey(); + Node newInit = entry.getValue(); + phi.setValueAt(phiInitIndex, (Value) newInit); + } + + if (from == loopBegin.loopEnd()) { + for (LoopCounter counter : loopBegin.counters()) { + counter.setInit(new IntegerAdd(counter.kind, counter.init(), counter.stride(), graph)); } - if (n instanceof Merge) { //add phis & counters - for (Node usage : n.dataUsages()) { - workData2.add(usage); + } + NodeMap> newExitValues = graph.createNodeMap(); + List exitPoints = new LinkedList(); + for (Node exit : loop.exits()) { + exitPoints.add(exit); + } + for (Entry entry : peeling.exits.entries()) { + Placeholder original = (Placeholder) entry.getKey(); + Placeholder newExit = entry.getValue(); + FixedNode next = original.next(); + EndNode oEnd = new EndNode(graph); + EndNode nEnd = new EndNode(graph); + Merge merge = new Merge(graph); + merge.setNext(next); + FrameState newState = newExit.stateAfter(); + merge.addEnd(nEnd); + merge.setStateAfter(newState); + //newState.merge(merge, original.stateAfter()); + merge.addEnd(oEnd); + original.setNext(oEnd); + newExit.setStateAfter(null); + newExit.replaceAndDelete(nEnd); + + exitPoints.add(nEnd); + } + + for (Entry entry : peeling.exits.entries()) { + Placeholder original = (Placeholder) entry.getKey(); + EndNode oEnd = (EndNode) original.next(); + Merge merge = oEnd.merge(); + EndNode nEnd = merge.endAt(1 - merge.phiPredecessorIndex(oEnd)); + FrameState newState = merge.stateAfter(); + NodeArray oInputs = original.stateAfter().inputs(); + NodeArray nInputs = newState.inputs(); + int oSize = oInputs.size(); + for (int i = 0; i < oSize; i++) { + Node newValue = nInputs.get(i); + Node originalValue = oInputs.get(i); + if (newValue != originalValue) { + NodeMap phiMap = newExitValues.get(originalValue); + if (phiMap == null) { + phiMap = graph.createNodeMap(); + newExitValues.set(originalValue, phiMap); + } + phiMap.set(original, (Value) originalValue); + phiMap.set(nEnd, (Value) newValue); + + phiMap = newExitValues.get(newValue); + if (phiMap == null) { + phiMap = graph.createNodeMap(); + newExitValues.set(newValue, phiMap); + } + phiMap.set(original, (Value) originalValue); + phiMap.set(nEnd, (Value) newValue); + } + } + /*Placeholder original = (Placeholder) entry.getKey(); + Merge merge = ((EndNode) original.next()).merge(); + FrameState newState = merge.stateAfter(); + NodeArray oInputs = original.stateAfter().inputs(); + NodeArray nInputs = newState.inputs(); + int oSize = oInputs.size(); + for (int i = 0; i < oSize; i++) { + Node newValue = nInputs.get(i); + Node originalValue = oInputs.get(i); + if (newValue != originalValue && newValue instanceof Phi) { + Phi newPhi = (Phi) newValue; + assert newPhi.valueAt(1) == originalValue; + NodeMap phiMap = newExitValues.get(originalValue); + if (phiMap == null) { + phiMap = graph.createNodeMap(); + newExitValues.set(originalValue, phiMap); + } + phiMap.set(merge, newPhi); + } + }*/ + } + for (Entry> entry : newExitValues.entries()) { + Value original = (Value) entry.getKey(); + NodeMap pointToValue = entry.getValue(); + for (Node exit : exitPoints) { + Node valueAtExit = pointToValue.get(exit); + if (valueAtExit == null) { + pointToValue.set(exit, original); } } } - inOrBefore.setIntersect(inOrAfter); - loopNodes.setUnion(inOrBefore); - return loopNodes; + + replaceValuesAtLoopExits(newExitValues, loop, exitPoints); + } + + private static void replaceValuesAtLoopExits(final NodeMap> newExitValues, Loop loop, List exitPoints) { + Graph graph = loop.loopBegin().graph(); + final NodeMap colors = graph.createNodeMap(); + + // prepare inital colors + for (Node exitPoint : exitPoints) { + colors.set(exitPoint, exitPoint); + } + + /*System.out.println("newExitValues"); + for (Entry> entry : newExitValues.entries()) { + System.out.println(" - " + entry.getKey() + " :"); + for (Entry entry2 : entry.getValue().entries()) { + System.out.println(" + " + entry2.getKey() + " -> " + entry2.getValue()); + } + }*/ + + // color + GraphUtil.colorCFGDown(colors, new ColoringLambda() { + @Override + public Node color(Iterable incomming, Merge merge) { + Node color = null; + for (Node c : incomming) { + if (c == null) { + return null; + } + if (color == null) { + color = c; + } else if (color != c) { + return merge; + } + } + return color; + } + @Override + public Node danglingColor(Iterable incomming, Merge merge) { + Node color = null; + for (Node c : incomming) { + if (color == null) { + color = c; + } else if (color != c) { + return merge; + } + } + assert color != null; + return color; + } + }); + + final NodeBitMap inOrBefore = inOrBefore(loop); + + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + Map debug = new HashMap(); + debug.put("loopExits", colors); + debug.put("inOrBefore", inOrBefore); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After coloring", graph, true, false, debug)); + } + + GraphUtil.splitFromColoring(colors, new ColorSplitingLambda(){ + @Override + public void fixSplit(Node oldNode, Node newNode, Node color) { + this.fixNode(newNode, color); + } + private Value getValueAt(Node point, NodeMap valueMap, CiKind kind) { + Value value = valueMap.get(point); + if (value != null) { + //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + value); + return value; + } + Merge merge = (Merge) point; + ArrayList values = new ArrayList(merge.phiPredecessorCount()); + Value v = null; + boolean createPhi = false; + for (EndNode end : merge.cfgPredecessors()) { + Value valueAt = getValueAt(colors.get(end), valueMap, kind); + if (v == null) { + v = valueAt; + } else if (v != valueAt) { + createPhi = true; + } + values.add(valueAt); + } + if (createPhi) { + Phi phi = new Phi(kind, merge, merge.graph()); + valueMap.set(point, phi); + for (EndNode end : merge.cfgPredecessors()) { + phi.addInput(getValueAt(colors.get(end), valueMap, kind)); + } + //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + phi); + return phi; + } else { + assert v != null; + valueMap.set(point, v); + //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + v); + return v; + } + } + @Override + public boolean explore(Node n) { + return !inOrBefore.isNew(n) && !inOrBefore.isMarked(n) && !(n instanceof Local) && !(n instanceof Constant); //TODO (gd) hum + } + @Override + public void fixNode(Node node, Node color) { + //System.out.println("fixNode(" + node + ", " + color + ")"); + for (int i = 0; i < node.inputs().size(); i++) { + Node input = node.inputs().get(i); + if (input == null || newExitValues.isNew(input)) { + continue; + } + NodeMap valueMap = newExitValues.get(input); + if (valueMap != null) { + Value replacement = getValueAt(color, valueMap, ((Value) input).kind); + node.inputs().set(i, replacement); + } + } + } + @Override + public Value fixPhiInput(Value input, Node color) { + if (newExitValues.isNew(input)) { + return input; + } + NodeMap valueMap = newExitValues.get(input); + if (valueMap != null) { + return getValueAt(color, valueMap, input.kind); + } + return input; + }}); + + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After split from colors", graph, true, false)); + } + } + + private static PeelingResult preparePeeling(Loop loop, FixedNode from) { + LoopBegin loopBegin = loop.loopBegin(); + Graph graph = loopBegin.graph(); + NodeBitMap marked = computeLoopNodesFrom(loopBegin, from); + GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + Map debug = new HashMap(); + debug.put("marked", marked); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After computeLoopNodesFrom", loopBegin.graph(), true, false, debug)); + } + if (from == loopBegin.loopEnd()) { + clearWithState(from, marked); + } + clearWithState(loopBegin, marked); + Map replacements = new HashMap(); + NodeMap phis = graph.createNodeMap(); + NodeMap exits = graph.createNodeMap(); + + for (Node exit : loop.exits()) { + if (marked.isMarked(exit.singlePredecessor())) { + Placeholder pExit = (Placeholder) exit; + marked.mark(pExit.stateAfter()); + Placeholder p = new Placeholder(graph); + replacements.put(exit, p); + exits.set(exit, p); + } + } + + for (Node n : marked) { + if (n instanceof Phi && ((Phi) n).merge() == loopBegin) { + Placeholder p = new Placeholder(graph); + replacements.put(n, p); + phis.set(n, p); + marked.clear(n); + } + for (Node input : n.dataInputs()) { + if (!marked.isMarked(input) && (!(input instanceof Phi) || ((Phi) input).merge() != loopBegin)) { + replacements.put(input, input); + } + } + } + + //GraalCompilation compilation = GraalCompilation.compilation(); + if (compilation.compiler.isObserved()) { + Map debug = new HashMap(); + debug.put("marked", marked); + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Before addDuplicate loop#" + loopBegin.id(), loopBegin.graph(), true, false, debug)); + } + + Map duplicates = graph.addDuplicate(marked, replacements); + + NodeMap dataOut = graph.createNodeMap(); + for (Node n : marked) { + for (Node usage : n.dataUsages()) { + if (!marked.isMarked(usage) + && !loop.nodes().isNew(usage) && loop.nodes().isMarked(usage) + && !((usage instanceof Phi) && ((Phi) usage).merge() != loopBegin)) { + dataOut.set(n, duplicates.get(n)); + break; + } + } + } + NodeMap phiInits = graph.createNodeMap(); + int backIndex = loopBegin.phiPredecessorIndex(loopBegin.loopEnd()); + int fowardIndex = loopBegin.phiPredecessorIndex(loopBegin.forwardEdge()); + for (Phi phi : loopBegin.phis()) { + Value backValue = phi.valueAt(backIndex); + if (marked.isMarked(backValue)) { + phiInits.set(phi, duplicates.get(backValue)); + } else if (backValue instanceof Phi && ((Phi) backValue).merge() == loopBegin) { + Phi backPhi = (Phi) backValue; + phiInits.set(phi, backPhi.valueAt(fowardIndex)); + } + } + + FixedNode newBegin = (FixedNode) duplicates.get(loopBegin.next()); + FixedNode newFrom = (FixedNode) duplicates.get(from == loopBegin.loopEnd() ? from.singlePredecessor() : from); + return new PeelingResult(newBegin, newFrom, exits, phis, phiInits, dataOut); + } + + private static NodeBitMap inOrBefore(Loop loop) { + Graph graph = loop.loopBegin().graph(); + NodeBitMap inOrBefore = graph.createNodeBitMap(); + NodeFlood work = graph.createNodeFlood(); + NodeBitMap loopNodes = loop.nodes(); + work.addAll(loopNodes); + for (Node n : work) { + inOrBefore.mark(n); + for (Node pred : n.predecessors()) { + work.add(pred); + } + if (n instanceof Phi) { // filter out data graph cycles + Phi phi = (Phi) n; + if (!phi.isDead()) { + int backIndex = -1; + Merge merge = phi.merge(); + if (!loopNodes.isNew(merge) && !loopNodes.isMarked(merge) && merge instanceof LoopBegin) { + LoopBegin phiLoop = (LoopBegin) merge; + backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd()); + } + for (int i = 0; i < phi.valueCount(); i++) { + if (i != backIndex) { + work.add(phi.valueAt(i)); + } + } + } + } else { + for (Node in : n.inputs()) { + if (in != null) { + work.add(in); + } + } + if (n instanceof LoopBegin) { + Loop p = loop.parent; + boolean isParent = false; + while (p != null) { + if (p.loopBegin() == n) { + isParent = true; + break; + } + p = p.parent; + } + if (!isParent) { + work.add(((LoopBegin) n).loopEnd()); + } + } + } + } + return inOrBefore; + } + + private static void markWithState(Node n, NodeBitMap map) { + map.mark(n); + if (n instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) n).stateAfter(); + if (stateAfter != null) { + map.mark(stateAfter); + } + } + } + + private static void clearWithState(Node n, NodeBitMap map) { + map.clear(n); + if (n instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) n).stateAfter(); + if (stateAfter != null) { + map.clear(stateAfter); + } + } } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Fri Jul 01 18:24:04 2011 +0200 @@ -121,6 +121,10 @@ return rethrowException; } + public RiMethod method() { + return method; + } + /** * Gets a copy of this frame state. */ @@ -420,6 +424,15 @@ return null; } + public StateSplit stateSplit() { + for (Node n : usages()) { + if (n instanceof StateSplit) { + return (StateSplit) n; + } + } + return null; + } + /** * The interface implemented by a client of {@link FrameState#forEachPhi(Merge, PhiProcedure)} and * {@link FrameState#forEachLivePhi(Merge, PhiProcedure)}. @@ -467,9 +480,17 @@ @Override public String toString() { + return super.toString(); + } + + public String toDetailedString() { StringBuilder sb = new StringBuilder(); String nl = String.format("%n"); - sb.append("[bci: ").append(bci).append("]").append(nl); + sb.append("[bci: ").append(bci).append("]"); + if (rethrowException()) { + sb.append(" rethrows Exception"); + } + sb.append(nl); for (int i = 0; i < localsSize(); ++i) { Value value = localAt(i); sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); diff -r 0affee9ff3a9 -r 5cdaa94cd622 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 Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java Fri Jul 01 18:24:04 2011 +0200 @@ -509,7 +509,7 @@ } public FrameState duplicateWithoutStack(int bci) { - FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, true, graph); + FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, false, graph); frameState.setOuterFrameState(outerFrameState()); return frameState; } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java Fri Jul 01 18:24:04 2011 +0200 @@ -95,18 +95,18 @@ return holder; } - @Override - public boolean equals(Object obj) { - if (obj instanceof HotSpotField) { - HotSpotField other = (HotSpotField) obj; - return other.offset == offset && other.holder.equals(holder()); - } - return false; - } +// @Override +// public boolean equals(Object obj) { +// if (obj instanceof HotSpotField) { +// HotSpotField other = (HotSpotField) obj; +// return other.offset == offset && other.holder.equals(holder()); +// } +// return false; +// } @Override public boolean isResolved() { - return offset != -1; + return holder.isResolved(); } @Override @@ -130,7 +130,7 @@ @Override public String toString() { - return "HotSpotField<" + holder.name() + "." + name + ">"; + return "HotSpotField<" + holder.name() + "." + name + ":" + offset + ">"; } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java Fri Jul 01 18:24:04 2011 +0200 @@ -150,4 +150,8 @@ return null; } + @Override + public RiField[] fields() { + return null; + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java Fri Jul 01 18:24:04 2011 +0200 @@ -48,6 +48,7 @@ private RiConstantPool pool; private RiType superType; private boolean superTypeSet; + private RiField[] fields; private HotSpotTypeResolvedImpl() { super(null); @@ -222,4 +223,11 @@ return ((HotSpotMethodResolved) method).uniqueConcreteMethod(); } + @Override + public RiField[] fields() { + if (fields == null) { + fields = compiler.getVMEntries().RiType_fields(this); + } + return fields; + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java Fri Jul 01 18:24:04 2011 +0200 @@ -201,4 +201,8 @@ throw unresolved("uniqueConcreteMethod"); } + @Override + public RiField[] fields() { + return null; + } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Fri Jul 01 18:24:04 2011 +0200 @@ -1043,7 +1043,6 @@ asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); // if we get an exact match: continue asm.jneq(slowPath, objHub, hub); - asm.shouldNotReachHere(); // -- out of line ------------------------------------------------------- asm.bindOutOfLine(slowPath); diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java Fri Jul 01 18:24:04 2011 +0200 @@ -87,9 +87,9 @@ void recordBailout(String reason); - RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved hotSpotTypeResolved); + RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved klass); - RiType RiType_superType(HotSpotTypeResolved hotSpotTypeResolved); + RiType RiType_superType(HotSpotTypeResolved klass); int getArrayLength(CiConstant array); @@ -97,5 +97,7 @@ RiType getRiType(CiConstant constant); + RiField[] RiType_fields(HotSpotTypeResolved klass); + // Checkstyle: resume } diff -r 0affee9ff3a9 -r 5cdaa94cd622 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java Fri Jul 01 18:15:05 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java Fri Jul 01 18:24:04 2011 +0200 @@ -141,5 +141,8 @@ return getType(o.getClass()); } + @Override + public native RiField[] RiType_fields(HotSpotTypeResolved klass); + // Checkstyle: resume } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java Fri Jul 01 18:24:04 2011 +0200 @@ -51,7 +51,7 @@ List children = new ArrayList(); children.add(g); if(g.getGraphs().size() == 1) { - //g.getGraphs().get(0).setName(g.getName() + " / " + g.getGraphs().get(0).getName()); + g.getGraphs().get(0).setName(g.getName() + " / " + g.getGraphs().get(0).getName()); result.add(new Pair>("", children)); } else { Pair> p = new Pair>(); diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Fri Jul 01 18:24:04 2011 +0200 @@ -173,7 +173,7 @@ assert nodes.get(n.getId()) == n; if (!scheduledNodes.contains(n)) { if (noBlock == null) { - noBlock = this.addBlock("no block"); + noBlock = this.addBlock("(no block)"); } noBlock.addNode(n.getId()); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Fri Jul 01 18:24:04 2011 +0200 @@ -221,30 +221,35 @@ @Override protected void end(String text) throws SAXException { + // NOTE: Some graphs intentionally don't provide blocks. Instead + // they later generate the blocks from other information such + // as node properties (example: ServerCompilerScheduler). + // Thus, we shouldn't assign nodes that don't belong to any + // block to some artificial block below unless blocks are + // defined and nodes are assigned to them. - // Recover from control flow input with missing information if (graph.getBlocks().size() > 0) { - boolean blockContainsNodes = false; + boolean blocksContainNodes = false; for (InputBlock b : graph.getBlocks()) { if (b.getNodes().size() > 0) { - blockContainsNodes = true; + blocksContainNodes = true; break; } } - if (!blockContainsNodes) { + if (!blocksContainNodes) { graph.clearBlocks(); blockConnections.clear(); } else { - + // Blocks and their nodes defined: add other nodes to an + // artificial "no block" block InputBlock noBlock = null; - for (InputNode n : graph.getNodes()) { if (graph.getBlock(n) == null) { if (noBlock == null) { - noBlock = graph.addBlock("none"); + noBlock = graph.addBlock("(no block)"); } - + noBlock.addNode(n.getId()); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Difference/nbproject/project.xml --- a/src/share/tools/IdealGraphVisualizer/Difference/nbproject/project.xml Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Difference/nbproject/project.xml Fri Jul 01 18:24:04 2011 +0200 @@ -14,6 +14,14 @@ 1.0 + + org.openide.util.lookup + + + + 8.6.1 + + com.sun.hotspot.igv.difference diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java --- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Fri Jul 01 18:24:04 2011 +0200 @@ -31,11 +31,13 @@ import com.sun.hotspot.igv.data.InputNode; import com.sun.hotspot.igv.data.Pair; import com.sun.hotspot.igv.data.Property; +import com.sun.hotspot.igv.data.services.Scheduler; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.openide.util.Lookup; /** * @@ -84,7 +86,19 @@ return createDiff(a, b, pairs); } + private static void ensureScheduled(InputGraph a) { + if (a.getBlocks().isEmpty()) { + Scheduler s = Lookup.getDefault().lookup(Scheduler.class); + a.clearBlocks(); + s.schedule(a); + a.ensureNodesInBlocks(); + } + } + private static InputGraph createDiff(InputGraph a, InputGraph b, Set pairs) { + ensureScheduled(a); + ensureScheduled(b); + Group g = new Group(); g.setMethod(a.getGroup().getMethod()); g.setAssembly(a.getGroup().getAssembly()); @@ -97,7 +111,10 @@ blocksMap.put(blk, diffblk); } for (InputBlock blk : b.getBlocks()) { - InputBlock diffblk = graph.addBlock(blk.getName()); + InputBlock diffblk = graph.getBlock(blk.getName()); + if (diffblk == null) { + diffblk = graph.addBlock(blk.getName()); + } blocksMap.put(blk, diffblk); } @@ -117,14 +134,16 @@ inputNodeMap.put(n, n2); inputNodeMap.put(nB, n2); graph.addNode(n2); - graph.setBlock(n2, blocksMap.get(a.getBlock(n))); + InputBlock block = blocksMap.get(a.getBlock(n)); + block.addNode(n2.getId()); markAsChanged(n2, n, nB); } for (InputNode n : nodesA) { InputNode n2 = new InputNode(n); graph.addNode(n2); - graph.setBlock(n2, blocksMap.get(a.getBlock(n))); + InputBlock block = blocksMap.get(a.getBlock(n)); + block.addNode(n2.getId()); markAsDeleted(n2); inputNodeMap.put(n, n2); } @@ -132,7 +151,7 @@ int curIndex = 0; for (InputNode n : nodesB) { InputNode n2 = new InputNode(n); - + // Find new ID for node of b, does not change the id property while (graph.getNode(curIndex) != null) { curIndex++; @@ -140,7 +159,8 @@ n2.setId(curIndex); graph.addNode(n2); - graph.setBlock(n2, blocksMap.get(b.getBlock(n))); + InputBlock block = blocksMap.get(b.getBlock(n)); + block.addNode(n2.getId()); markAsNew(n2); inputNodeMap.put(n, n2); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/FilterWindow/src/com/sun/hotspot/igv/filterwindow/layer.xml --- a/src/share/tools/IdealGraphVisualizer/FilterWindow/src/com/sun/hotspot/igv/filterwindow/layer.xml Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/src/com/sun/hotspot/igv/filterwindow/layer.xml Fri Jul 01 18:24:04 2011 +0200 @@ -18,8 +18,11 @@ - - + + + + + diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalColoringFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalColoringFilter.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,79 @@ +/* + * 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.sun.hotspot.igv.graal.filters; + +import com.sun.hotspot.igv.data.Properties; +import com.sun.hotspot.igv.filter.AbstractFilter; +import com.sun.hotspot.igv.graph.Diagram; +import com.sun.hotspot.igv.graph.Figure; +import java.awt.Color; +import java.util.List; + +public class GraalColoringFilter extends AbstractFilter { + + private String colorName; + + public GraalColoringFilter(String colorName) { + this.colorName = colorName; + } + + public String getName() { + return "Graal Coloring Filter (" + colorName + ")"; + } + + public void apply(Diagram d) { + List
figures = d.getFigures(); + int colors = 0; + for (Figure f : figures) { + Properties p = f.getProperties(); + final String prop = p.get(colorName + "Color"); + if (prop == null) { + continue; + } + try { + int color = Integer.parseInt(prop); + if (color > colors) { + colors = color; + } + } catch (NumberFormatException nfe) { + // nothing to do + } + } + colors++; + for (Figure f : figures) { + Properties p = f.getProperties(); + final String prop = p.get(colorName + "Color"); + if (prop == null) { + continue; + } + try { + int color = Integer.parseInt(prop); + Color c = Color.getHSBColor((float) color / colors, 1.0f, 0.7f); + f.setColor(c); + } catch (NumberFormatException nfe) { + // nothing to do + } + } + } +} diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalSlotFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalSlotFilter.java Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,66 @@ +/* + * 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.sun.hotspot.igv.graal.filters; + +import com.sun.hotspot.igv.filter.AbstractFilter; +import com.sun.hotspot.igv.graph.Diagram; +import com.sun.hotspot.igv.graph.Figure; +import com.sun.hotspot.igv.graph.InputSlot; +import com.sun.hotspot.igv.graph.OutputSlot; +import com.sun.hotspot.igv.graph.Slot; +import java.util.ArrayList; +import java.util.List; + +/** + * Filter that hides slots with no connections. + */ +public class GraalSlotFilter extends AbstractFilter { + + public GraalSlotFilter() { + } + + public String getName() { + return "Graal Slot Filter"; + } + + public void apply(Diagram d) { + List
figures = d.getFigures(); + for (Figure f : figures) { + List remove = new ArrayList(); + for (InputSlot is : f.getInputSlots()) { + if (is.getConnections().isEmpty()) { + remove.add(is); + } + } + for (OutputSlot os : f.getOutputSlots()) { + if (os.getConnections().isEmpty()) { + remove.add(os); + } + } + for (Slot s : remove) { + f.removeSlot(s); + } + } + } +} diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter Fri Jul 01 18:24:04 2011 +0200 @@ -1,9 +1,11 @@ colorize("name", ".*", white); -colorize("name", "StartNode|EndNode|LoopBegin|LoopEnd|Return", red); +colorize("name", "StartNode|EndNode|LoopBegin|LoopEnd|Return", orange); colorize("name", "Phi:.*", magenta); colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0)); colorize("name", "If", pink); colorize("name", "const.*", new java.awt.Color(0.7, 0.7, 0.7)); colorize("name", "Local", new java.awt.Color(0.85, 0.85, 0.85)); colorize("name", "\\+|-|\\*|/", cyan); -colorize("name", "Comp .*", yellow); \ No newline at end of file +colorize("name", "Comp .*", yellow); + +colorize("notInOwnBlock", "true", red); \ No newline at end of file diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/slots.filter --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/slots.filter Fri Jul 01 18:24:04 2011 +0200 @@ -0,0 +1,2 @@ +var f = new com.sun.hotspot.igv.graal.filters.GraalSlotFilter(); +f.apply(graph); diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml Fri Jul 01 18:24:04 2011 +0200 @@ -9,5 +9,9 @@ + + + + diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/genfiles.properties --- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/genfiles.properties Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/genfiles.properties Fri Jul 01 18:24:04 2011 +0200 @@ -1,5 +1,5 @@ # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=ac7a776e +nbproject/build-impl.xml.data.CRC32=f0880ef0 nbproject/build-impl.xml.script.CRC32=9388e04e nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.45.1 diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/project.xml --- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/project.xml Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/project.xml Fri Jul 01 18:24:04 2011 +0200 @@ -63,6 +63,15 @@ + org.netbeans.modules.diff + + + + 1 + 1.32.1.42.1 + + + org.openide.util diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.form --- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.form Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.form Fri Jul 01 18:24:04 2011 +0200 @@ -1,4 +1,4 @@ - +
diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.java Fri Jul 01 18:24:04 2011 +0200 @@ -24,24 +24,39 @@ package com.sun.hotspot.igv.graphtexteditor; import com.sun.hotspot.igv.data.ChangedListener; +import com.sun.hotspot.igv.data.Properties; import com.sun.hotspot.igv.texteditor.*; import com.sun.hotspot.igv.data.InputGraph; import com.sun.hotspot.igv.data.Pair; +import com.sun.hotspot.igv.data.Property; import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.graph.services.DiagramProvider; import com.sun.hotspot.igv.graphtotext.services.GraphToTextConverter; import com.sun.hotspot.igv.selectioncoordinator.SelectionCoordinator; +import com.sun.hotspot.igv.structuredtext.MultiElement; import com.sun.hotspot.igv.structuredtext.StructuredText; import com.sun.hotspot.igv.util.LookupHistory; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.IOException; import java.io.Serializable; +import java.io.StringReader; import java.util.Collection; import java.util.logging.Logger; +import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; +import javax.swing.JToolBar; +import org.netbeans.api.diff.Diff; +import org.netbeans.api.diff.DiffView; +import org.netbeans.api.diff.StreamSource; import org.openide.util.Lookup; import org.openide.util.LookupEvent; import org.openide.util.LookupListener; @@ -52,6 +67,7 @@ /** * @author Thomas Wuerthinger + * @author Peter Hofer */ final class TextTopComponent extends TopComponent implements LookupListener { @@ -65,12 +81,17 @@ private JSplitPane splitPane; private CardLayout cardLayout; private JPanel cardLayoutPanel; - private boolean firstTimeSlider = true; + private JComboBox sourceCombo; + private boolean firstTimeSplitter = true; + private JPanel textDiffPanel; + private static final String TWO_GRAPHS_TEXT_DIFF = "twoGraphsTextDiff"; private static final String TWO_GRAPHS = "twoGraphs"; private static final String ONE_GRAPH = "oneGraph"; private static final String NO_GRAPH = "noGraph"; + private static final String GRAPH_TEXT_REPRESENTATION = "< Graph Text Representation >"; + private DiagramProvider currentDiagramProvider; private TextTopComponent() { @@ -78,16 +99,28 @@ setName(NbBundle.getMessage(TextTopComponent.class, "CTL_TextTopComponent")); setToolTipText(NbBundle.getMessage(TextTopComponent.class, "HINT_TextTopComponent")); + setLayout(new BorderLayout()); + + // Selector for displayed data + JToolBar sourceSelectBar = new JToolBar(); + sourceSelectBar.setLayout(new BorderLayout()); + sourceSelectBar.setFloatable(false); + sourceSelectBar.add(new JLabel("Show: "), BorderLayout.WEST); + sourceCombo = new JComboBox(); + sourceCombo.addItem(GRAPH_TEXT_REPRESENTATION); + sourceCombo.addItemListener(sourceSelectionListener); + sourceSelectBar.add(sourceCombo, BorderLayout.CENTER); + add(sourceSelectBar, BorderLayout.NORTH); + // Card layout for three different views. cardLayout = new CardLayout(); cardLayoutPanel = new JPanel(cardLayout); - this.setLayout(new BorderLayout()); - this.add(cardLayoutPanel, BorderLayout.CENTER); + add(cardLayoutPanel, BorderLayout.CENTER); // No graph selected. - JLabel noGraphLabel = new JLabel("No graph opened"); - noGraphLabel.setBackground(Color.red); - //noGraphPanel.add(noGraphLabel); + JLabel noGraphLabel = new JLabel("No graph open.", JLabel.CENTER); + noGraphLabel.setOpaque(true); + noGraphLabel.setBackground(Color.WHITE); cardLayoutPanel.add(noGraphLabel, NO_GRAPH); // Single graph selected. @@ -97,10 +130,31 @@ // Graph difference => show split pane with two graphs. splitPane = new JSplitPane(); leftEditor = new TextEditor(); - splitPane.setLeftComponent(leftEditor.getComponent()); rightEditor = new TextEditor(); - splitPane.setRightComponent(rightEditor.getComponent()); + // Work around a problem with JSplitPane and the NetBeans editor: + // setDividerLocation() doesn't work when the split pane has not been + // layouted and painted yet. JSplitPane then initially uses a tiny width + // for the left editor component, which causes the editor to calculate + // invalid offsets and constantly throw exceptions, particularly on + // mouse events. Thus, defer adding the two components and setting the + // divider's location. + splitPane.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + if (firstTimeSplitter && splitPane.getWidth() > 0) { + splitPane.setLeftComponent(leftEditor.getComponent()); + splitPane.setRightComponent(rightEditor.getComponent()); + splitPane.setDividerLocation(0.5); + firstTimeSplitter = false; + } + } + }); cardLayoutPanel.add(splitPane, TWO_GRAPHS); + + // Text difference => NetBeans diff view + // Diff component is created and added on demand + textDiffPanel = new JPanel(new BorderLayout()); + cardLayoutPanel.add(textDiffPanel, TWO_GRAPHS_TEXT_DIFF); } @@ -129,23 +183,104 @@ return text; } - private void updateDiagram(Diagram diagram) { + private StructuredText createStructuredPlainText(String name, String text) { + StructuredText structured = new StructuredText(name); + MultiElement multi = new MultiElement(); + multi.print(text); + structured.addChild(multi); + return structured; + } + private ItemListener sourceSelectionListener = new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + if (e.getItem() == GRAPH_TEXT_REPRESENTATION) { + displayDiagram(lastDiagram); + } else { + displayGroupProperty(lastDiagram, (String) e.getItem()); + } + } + } + }; + + private void setDiagram(Diagram diagram) { if (diagram == lastDiagram) { // No change => return. return; } - lastDiagram = diagram; + // Rebuild combobox choices + Object selection = sourceCombo.getSelectedItem(); + sourceCombo.removeAllItems(); + sourceCombo.addItem(GRAPH_TEXT_REPRESENTATION); + if (diagram != null) { + if (diagram.getGraph().getSourceGraphs() != null) { + // Diff graph with source graphs with possibly different groups: + // show properties from both graphs + Pair sourceGraphs = diagram.getGraph().getSourceGraphs(); + Properties props = new Properties(sourceGraphs.getLeft().getGroup().getProperties()); + if (sourceGraphs.getLeft().getGroup() != sourceGraphs.getRight().getGroup()) { + props.add(sourceGraphs.getRight().getGroup().getProperties()); + } + for (Property p : props) { + sourceCombo.addItem(p.getName()); + } + } else { + // Single graph + for (Property p : diagram.getGraph().getGroup().getProperties()) { + sourceCombo.addItem(p.getName()); + } + } + } + // NOTE: The following triggers a display update. + sourceCombo.setSelectedItem(selection); + if (sourceCombo.getSelectedItem() == null) { + // previously selected property doesn't exist in new graph's group: + // default to show graph representation + sourceCombo.setSelectedItem(GRAPH_TEXT_REPRESENTATION); + } + } + + private void displayGroupProperty(Diagram diagram, String property) { + if (diagram == null) { + showCard(NO_GRAPH); + } else if (diagram.getGraph().getSourceGraphs() != null) { + showCard(TWO_GRAPHS_TEXT_DIFF); + textDiffPanel.removeAll(); + try { + Pair sourceGraphs = diagram.getGraph().getSourceGraphs(); + + String ltext = sourceGraphs.getLeft().getGroup().getProperties().get(property); + if (ltext == null) { + ltext = ""; + } + StreamSource leftsrc = StreamSource.createSource("left", sourceGraphs.getLeft().getName(), "text/plain", new StringReader(ltext)); + + String rtext = sourceGraphs.getRight().getGroup().getProperties().get(property); + if (rtext == null) { + rtext = ""; + } + StreamSource rightsrc = StreamSource.createSource("right", sourceGraphs.getRight().getName(), "text/plain", new StringReader(rtext)); + + DiffView view = Diff.getDefault().createDiff(leftsrc, rightsrc); + textDiffPanel.add(view.getComponent(), BorderLayout.CENTER); + } catch (IOException e) { + throw new RuntimeException(e); + } + textDiffPanel.revalidate(); // required when card was visible before + } else { + showCard(ONE_GRAPH); + String text = diagram.getGraph().getGroup().getProperties().get(property); + singleEditor.setStructuredText(createStructuredPlainText(diagram.getGraph().getName(), text)); + } + } + + private void displayDiagram(Diagram diagram) { if (diagram == null) { showCard(NO_GRAPH); } else if (diagram.getGraph().getSourceGraphs() != null) { showCard(TWO_GRAPHS); - if (firstTimeSlider) { - splitPane.setDividerLocation(0.5); - } - firstTimeSlider = false; Pair graphs = diagram.getGraph().getSourceGraphs(); leftEditor.setStructuredText(convert(graphs.getLeft(), diagram)); rightEditor.setStructuredText(convert(graphs.getRight(), diagram)); @@ -161,17 +296,16 @@ SelectionCoordinator.getInstance().getHighlightedChangedEvent().fire(); } } - + private ChangedListener diagramChangedListener = new ChangedListener() { public void changed(DiagramProvider source) { - updateDiagram(source.getDiagram()); + setDiagram(source.getDiagram()); } }; - private void updateDiagramProvider(DiagramProvider provider) { - + private void setDiagramProvider(DiagramProvider provider) { if (provider == currentDiagramProvider) { return; } @@ -184,9 +318,9 @@ if (currentDiagramProvider != null) { currentDiagramProvider.getChangedEvent().addListener(diagramChangedListener); - updateDiagram(currentDiagramProvider.getDiagram()); + setDiagram(currentDiagramProvider.getDiagram()); } else { - updateDiagram(null); + setDiagram(null); } } @@ -201,7 +335,7 @@ p = LookupHistory.getLast(DiagramProvider.class); } - updateDiagramProvider(p); + setDiagramProvider(p); } /** This method is called from within the constructor to @@ -258,7 +392,7 @@ public void componentOpened() { DiagramProvider p = LookupHistory.getLast(DiagramProvider.class); - updateDiagramProvider(p); + setDiagramProvider(p); Lookup.Template tpl = new Lookup.Template(DiagramProvider.class); result = Utilities.actionsGlobalContext().lookup(tpl); @@ -269,7 +403,7 @@ public void componentClosed() { result.removeLookupListener(this); result = null; - updateDiagramProvider(null); + setDiagramProvider(null); } /** replaces this in object stream */ diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java Fri Jul 01 18:24:04 2011 +0200 @@ -530,9 +530,11 @@ } }; private static final Comparator nodeProcessingDownComparator = new Comparator() { - public int compare(LayoutNode n1, LayoutNode n2) { if (n1.vertex == null) { + if (n2.vertex == null) { + return 0; + } return -1; } if (n2.vertex == null) { @@ -545,6 +547,9 @@ public int compare(LayoutNode n1, LayoutNode n2) { if (n1.vertex == null) { + if (n2.vertex == null) { + return 0; + } return -1; } if (n2.vertex == null) { diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java --- a/src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java Fri Jul 01 18:24:04 2011 +0200 @@ -212,7 +212,7 @@ for (InputNode n : graph.getNodes()) { if (graph.getBlock(n) == null) { if (noBlock == null) { - noBlock = graph.addBlock("none"); + noBlock = graph.addBlock("(no block)"); blocks.add(noBlock); } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/Bundle.properties --- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/Bundle.properties Fri Jul 01 18:15:05 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -OpenIDE-Module-Name=Text Editor diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/layer.xml --- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/layer.xml Fri Jul 01 18:15:05 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/preferences.xml --- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/preferences.xml Fri Jul 01 18:15:05 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - - - - - - diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Text Editor/build/depcache/dependencies.txt --- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/depcache/dependencies.txt Fri Jul 01 18:15:05 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -||:at.ssw.visualizer.texteditor.Editor -at.ssw.visualizer.core.selection.SelectionManager -at.ssw.visualizer.core.selection.SelectionProvider -org.openide.text.CloneableEditor -javax.swing.JEditorPane -at.ssw.visualizer.texteditor.Editor$2 -at.ssw.visualizer.texteditor.Editor$1 -at.ssw.visualizer.core.selection.Selection -at.ssw.visualizer.texteditor.Editor -at.ssw.visualizer.texteditor.EditorSupport -||:at.ssw.visualizer.texteditor.EditorSupport -java.lang.StringBuilder -java.lang.UnsupportedOperationException -org.openide.windows.CloneableOpenSupport$Env -org.openide.text.CloneableEditorSupport -at.ssw.visualizer.texteditor.EditorSupport$Env -javax.swing.text.StyledDocument -org.openide.windows.CloneableOpenSupport -at.ssw.visualizer.texteditor.model.Text -org.openide.cookies.EditorCookie$Observable -com.sun.hotspot.igv.data.InputGraph -org.openide.cookies.EditCookie -org.openide.cookies.EditorCookie -org.openide.text.CloneableEditorSupport$Env -at.ssw.visualizer.texteditor.EditorSupport -com.sun.hotspot.igv.data.Group -||:at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory -java.lang.Object -at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory -org.netbeans.editor.SideBarFactory -at.ssw.visualizer.texteditor.fold.FoldManager -org.netbeans.editor.CodeFoldingSideBar -||:at.ssw.visualizer.texteditor.model.FoldingRegion -at.ssw.visualizer.texteditor.model.FoldingRegion -at.ssw.visualizer.texteditor.model.TextRegion -||:at.ssw.visualizer.texteditor.tooltip.StyledToolTip -java.awt.Color -javax.swing.border.LineBorder -java.awt.BorderLayout -java.lang.StringBuilder -java.awt.Dimension -at.ssw.visualizer.texteditor.tooltip.StyledToolTip -javax.swing.JEditorPane -javax.swing.JPanel -||:at.ssw.visualizer.texteditor.model.TextRegion -java.lang.Object -at.ssw.visualizer.texteditor.model.TextRegion -||:at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1 -java.lang.Object -at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent -at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1 -javax.swing.event.ChangeListener -||:at.ssw.visualizer.texteditor.model.TextBuilder -java.lang.StringBuilder -com.sun.hotspot.igv.data.InputBlock -java.util.HashSet -java.util.Set -java.util.List -java.util.ArrayList -at.ssw.visualizer.texteditor.model.Text -at.ssw.visualizer.texteditor.model.TextBuilder -java.util.Iterator -java.util.HashMap -java.util.Map -[Lat.ssw.visualizer.texteditor.model.FoldingRegion; -at.ssw.visualizer.texteditor.model.FoldingRegion -java.lang.Object -java.lang.String -||:at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent -at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent -javax.swing.JScrollPane -at.ssw.visualizer.core.selection.SelectionManager -javax.swing.JEditorPane -javax.swing.BorderFactory -java.awt.BorderLayout -com.sun.hotspot.igv.data.InputGraph -[Lcom.sun.hotspot.igv.data.InputBlock; -at.ssw.visualizer.core.selection.Selection -org.openide.windows.TopComponent -at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1 -java.util.Arrays -||:at.ssw.visualizer.texteditor.tooltip.ToolTipAction -at.ssw.visualizer.texteditor.model.Scanner -org.netbeans.editor.PopupManager -org.netbeans.editor.Utilities -org.netbeans.editor.TokenID -org.netbeans.editor.PopupManager$HorizontalBounds -org.netbeans.modules.editor.NbEditorKit$NbBuildToolTipAction -org.netbeans.editor.BaseDocument -org.netbeans.editor.EditorUI -at.ssw.visualizer.texteditor.model.Text -javax.swing.plaf.TextUI -java.awt.event.MouseEvent -org.netbeans.modules.editor.NbEditorKit -org.netbeans.editor.ext.ToolTipSupport -at.ssw.visualizer.texteditor.tooltip.ToolTipAction -javax.swing.text.JTextComponent -at.ssw.visualizer.texteditor.tooltip.StyledToolTip -org.netbeans.editor.PopupManager$Placement -||:at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory -java.lang.Object -org.netbeans.spi.editor.fold.FoldManagerFactory -at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory -at.ssw.visualizer.texteditor.fold.FoldManager -||:at.ssw.visualizer.core.selection.Selection -[Ljavax.swing.event.ChangeListener; -at.ssw.visualizer.core.selection.Selection$1 -javax.swing.event.ChangeListener -java.util.List -java.util.ArrayList -at.ssw.visualizer.core.selection.SelectionManager -java.lang.Class -java.util.HashMap -java.util.Map -javax.swing.event.ChangeEvent -at.ssw.visualizer.core.selection.Selection -java.lang.Object -javax.swing.Timer -||:at.ssw.visualizer.texteditor.model.BlockRegion -at.ssw.visualizer.texteditor.model.BlockRegion -at.ssw.visualizer.texteditor.model.TextRegion -||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory -at.ssw.visualizer.texteditor.highlight.HighlightsContainer -at.ssw.visualizer.texteditor.model.Text -org.netbeans.spi.editor.highlighting.HighlightsLayerFactory -org.netbeans.spi.editor.highlighting.HighlightsLayer -java.lang.Object -javax.swing.text.Document -org.netbeans.spi.editor.highlighting.ZOrder -org.netbeans.spi.editor.highlighting.HighlightsLayerFactory$Context -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory -||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer -javax.swing.text.JTextComponent -org.netbeans.spi.editor.highlighting.support.AbstractHighlightsContainer -org.netbeans.api.editor.mimelookup.MimeLookup -org.openide.util.WeakListeners -org.netbeans.api.editor.mimelookup.MimePath -javax.swing.text.SimpleAttributeSet -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory -org.openide.util.Lookup -javax.swing.event.CaretListener -at.ssw.visualizer.texteditor.highlight.HighlightsContainer -at.ssw.visualizer.texteditor.model.Text -at.ssw.visualizer.texteditor.model.Scanner -org.netbeans.api.editor.settings.FontColorSettings -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1 -javax.swing.text.Caret -org.netbeans.editor.TokenID -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence -javax.swing.text.Document -||:at.ssw.visualizer.core.selection.Selection$1 -java.lang.Object -at.ssw.visualizer.core.selection.Selection -at.ssw.visualizer.core.selection.Selection$1 -java.awt.event.ActionListener -||:at.ssw.visualizer.texteditor.model.HoverParser -java.lang.Object -java.util.Iterator -java.lang.String -java.lang.StringBuilder -java.lang.UnsupportedOperationException -at.ssw.visualizer.texteditor.model.HoverParser -||:at.ssw.visualizer.texteditor.Editor$2 -at.ssw.visualizer.texteditor.Editor -java.util.ArrayList -javax.swing.event.CaretEvent -java.util.List -[Lcom.sun.hotspot.igv.data.InputBlock; -com.sun.hotspot.igv.data.InputBlock -java.util.Map -java.util.Collection -at.ssw.visualizer.core.selection.Selection -at.ssw.visualizer.texteditor.model.BlockRegion -java.util.Iterator -javax.swing.event.CaretListener -at.ssw.visualizer.texteditor.Editor$2 -at.ssw.visualizer.texteditor.model.Text -java.lang.Math -java.lang.Object -javax.swing.JEditorPane -javax.swing.text.Document -||:at.ssw.visualizer.texteditor.EditorSupport$Env -java.lang.UnsupportedOperationException -org.openide.text.CloneableEditorSupport -at.ssw.visualizer.texteditor.EditorSupport$Env -java.beans.VetoableChangeSupport -at.ssw.visualizer.texteditor.model.Text -java.io.ByteArrayInputStream -java.io.IOException -java.lang.Object -at.ssw.visualizer.texteditor.EditorSupport -org.openide.text.CloneableEditorSupport$Env -java.beans.PropertyChangeSupport -java.lang.String -||:at.ssw.visualizer.texteditor.Editor$1 -java.lang.Math -at.ssw.visualizer.texteditor.model.BlockRegion -javax.swing.event.ChangeListener -at.ssw.visualizer.texteditor.model.Text -javax.swing.JEditorPane -java.util.Map -[Lcom.sun.hotspot.igv.data.InputBlock; -at.ssw.visualizer.texteditor.Editor$1 -at.ssw.visualizer.core.selection.Selection -java.lang.Object -javax.swing.text.Document -at.ssw.visualizer.texteditor.Editor -java.util.Arrays -||:at.ssw.visualizer.texteditor.model.Text -java.lang.String -[Lat.ssw.visualizer.texteditor.model.TextRegion; -java.lang.Object -java.util.Iterator -java.util.Map -java.util.Set -at.ssw.visualizer.texteditor.model.Text -at.ssw.visualizer.texteditor.model.TextRegion -||:at.ssw.visualizer.core.selection.SelectionProvider -java.lang.Object -at.ssw.visualizer.core.selection.SelectionProvider -||:at.ssw.visualizer.texteditor.EditorKit -javax.swing.Action -at.ssw.visualizer.texteditor.tooltip.ToolTipAction -at.ssw.visualizer.texteditor.EditorKit -org.netbeans.modules.editor.NbEditorKit -javax.swing.text.TextAction -||:at.ssw.visualizer.core.selection.SelectionManager -at.ssw.visualizer.core.selection.Selection -java.lang.Object -at.ssw.visualizer.core.selection.SelectionManager -||:at.ssw.visualizer.texteditor.model.Scanner -at.ssw.visualizer.texteditor.model.Scanner -javax.swing.text.BadLocationException -java.lang.Math -java.util.Set -java.util.BitSet -java.lang.Class -java.util.logging.Level -java.util.logging.Logger -javax.swing.text.Document -java.lang.String -org.netbeans.editor.Syntax -||:at.ssw.visualizer.texteditor.fold.FoldManager -at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory -javax.swing.text.BadLocationException -at.ssw.visualizer.texteditor.fold.FoldManager -org.netbeans.api.editor.fold.FoldType -at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory -org.netbeans.spi.editor.fold.FoldManager -at.ssw.visualizer.texteditor.model.Text -java.lang.Class -java.util.logging.Level -java.util.logging.Logger -at.ssw.visualizer.texteditor.model.FoldingRegion -java.lang.Object -org.netbeans.api.editor.fold.FoldHierarchy -javax.swing.text.Document -javax.swing.text.JTextComponent -org.netbeans.spi.editor.fold.FoldOperation -||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1 -java.lang.Object -javax.swing.event.CaretListener -at.ssw.visualizer.texteditor.highlight.HighlightsContainer -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1 -javax.swing.text.Document -||:at.ssw.visualizer.texteditor.hyperlink.HyperlinkProvider -at.ssw.visualizer.texteditor.model.Scanner -org.netbeans.editor.Utilities -at.ssw.visualizer.texteditor.hyperlink.HyperlinkProvider -org.netbeans.editor.TokenID -org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider -at.ssw.visualizer.texteditor.model.Text -java.lang.Object -javax.swing.text.Document -at.ssw.visualizer.texteditor.model.TextRegion -javax.swing.text.JTextComponent -||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence -java.lang.Object -org.netbeans.spi.editor.highlighting.HighlightsSequence -at.ssw.visualizer.texteditor.highlight.HighlightsContainer -at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence -at.ssw.visualizer.texteditor.model.TextRegion diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/Text Editor/build/no-license.txt --- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/no-license.txt Fri Jul 01 18:15:05 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -[NO LICENSE SPECIFIED] \ No newline at end of file diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Fri Jul 01 18:24:04 2011 +0200 @@ -60,6 +60,7 @@ import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -1141,11 +1142,9 @@ Rectangle r = w.getBounds(); Point p = w.getLocation(); centerRectangle(new Rectangle(p.x, p.y, r.width, r.height)); - } public void gotoFigure(final Figure f) { - if (!isVisible(f)) { showFigure(f); } @@ -1153,7 +1152,7 @@ FigureWidget fw = getWidget(f); if (fw != null) { centerWidget(fw); - getModel().setSelectedNodes(f.getSource().getSourceNodesAsSet()); + setSelection(Arrays.asList(f)); } } diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java Fri Jul 01 18:24:04 2011 +0200 @@ -41,7 +41,7 @@ } public String getName() { - return "Expand Predecessors"; + return "Expand Above"; } @Override diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java Fri Jul 01 18:24:04 2011 +0200 @@ -41,7 +41,7 @@ } public String getName() { - return "Expand Successors"; + return "Expand Below"; } @Override diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java Fri Jul 01 18:24:04 2011 +0200 @@ -271,10 +271,10 @@ public JPopupMenu getPopupMenu(Widget widget, Point point) { JPopupMenu m = diagramScene.createPopupMenu(); - JMenu predecessors = new JMenu("Predecessors"); + JMenu predecessors = new JMenu("Nodes Above"); addFigureToSubMenu(predecessors, getFigure(), false, DEPTH); - JMenu successors = new JMenu("Successors"); + JMenu successors = new JMenu("Nodes Below"); addFigureToSubMenu(successors, getFigure(), true, DEPTH); m.addSeparator(); @@ -308,14 +308,13 @@ } public void addFigureToMenu(JMenu m, final Figure f, boolean successor, int depth) { - Action a = diagramScene.createGotoAction(f); m.add(a); if (depth > 0) { - String name = "Predecessors"; + String name = "Nodes Above"; if (successor) { - name = "Successors"; + name = "Nodes Below"; } JMenu subMenu = new JMenu(name); diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/tools/IdealGraphVisualizer/nbproject/platform.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Fri Jul 01 18:24:04 2011 +0200 @@ -56,21 +56,16 @@ org.netbeans.modules.dbapi,\ org.netbeans.modules.defaults,\ org.netbeans.modules.derby,\ - org.netbeans.modules.diff,\ org.netbeans.modules.dlight.nativeexecution,\ org.netbeans.modules.dlight.terminal,\ org.netbeans.modules.editor.bookmarks,\ org.netbeans.modules.editor.bracesmatching,\ org.netbeans.modules.editor.codetemplates,\ org.netbeans.modules.editor.completion,\ - org.netbeans.modules.editor.errorstripe,\ - org.netbeans.modules.editor.errorstripe.api,\ org.netbeans.modules.editor.guards,\ org.netbeans.modules.editor.indent.project,\ org.netbeans.modules.editor.kit,\ org.netbeans.modules.editor.macros,\ - org.netbeans.modules.editor.plain,\ - org.netbeans.modules.editor.plain.lib,\ org.netbeans.modules.editor.structure,\ org.netbeans.modules.extbrowser,\ org.netbeans.modules.extexecution,\ @@ -105,13 +100,11 @@ org.netbeans.modules.lexer.nbbridge,\ org.netbeans.modules.localhistory,\ org.netbeans.modules.mercurial,\ - org.netbeans.modules.options.editor,\ org.netbeans.modules.parsing.api,\ org.netbeans.modules.parsing.lucene,\ org.netbeans.modules.print.editor,\ org.netbeans.modules.project.ant,\ org.netbeans.modules.project.libraries,\ - org.netbeans.modules.projectapi,\ org.netbeans.modules.projectui,\ org.netbeans.modules.projectui.buildmenu,\ org.netbeans.modules.projectuiapi,\ diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Jul 01 18:24:04 2011 +0200 @@ -209,10 +209,12 @@ template(CiRegister_klass, com_sun_cri_ci_CiRegister, Opt) \ template(CiCodePos_klass, com_sun_cri_ci_CiCodePos, Opt) \ template(CiConstant_klass, com_sun_cri_ci_CiConstant, Opt) \ + template(CiVirtualObject_klass, com_sun_cri_ci_CiVirtualObject, Opt) \ template(CiKind_klass, com_sun_cri_ci_CiKind, Opt) \ template(CiRuntimeCall_klass, com_sun_cri_ci_CiRuntimeCall, Opt) \ template(RiMethod_klass, com_sun_cri_ri_RiMethod, Opt) \ template(RiType_klass, com_sun_cri_ri_RiType, Opt) \ + template(RiField_klass, com_sun_cri_ri_RiField, Opt) \ template(RiExceptionHandler_klass, com_sun_cri_ri_RiExceptionHandler, Opt) \ template(RiTypeProfile_klass, com_sun_cri_ri_RiTypeProfile, Opt) \ diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Jul 01 18:24:04 2011 +0200 @@ -258,18 +258,18 @@ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \ \ /* support for graal */ \ - template(com_sun_hotspot_graal_VMExits, "com/oracle/max/graal/runtime/VMExits") \ + template(com_sun_hotspot_graal_VMExits, "com/oracle/max/graal/runtime/VMExits") \ template(com_sun_hotspot_graal_HotSpotMethodResolved, "com/oracle/max/graal/runtime/HotSpotMethodResolvedImpl") \ - template(com_sun_hotspot_graal_HotSpotTargetMethod, "com/oracle/max/graal/runtime/HotSpotTargetMethod") \ - template(com_sun_hotspot_graal_HotSpotField, "com/oracle/max/graal/runtime/HotSpotField") \ - template(com_sun_graal_graalOptions, "com/sun/graal/graalOptions") \ - template(com_sun_hotspot_graal_HotSpotOptions, "com/oracle/max/graal/runtime/HotSpotOptions") \ - template(com_sun_hotspot_graal_HotSpotTypeResolved, "com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl") \ - template(com_sun_hotspot_graal_HotSpotType, "com/oracle/max/graal/runtime/HotSpotType") \ + template(com_sun_hotspot_graal_HotSpotTargetMethod, "com/oracle/max/graal/runtime/HotSpotTargetMethod") \ + template(com_sun_hotspot_graal_HotSpotField, "com/oracle/max/graal/runtime/HotSpotField") \ + template(com_sun_graal_graalOptions, "com/sun/graal/graalOptions") \ + template(com_sun_hotspot_graal_HotSpotOptions, "com/oracle/max/graal/runtime/HotSpotOptions") \ + template(com_sun_hotspot_graal_HotSpotTypeResolved, "com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl") \ + template(com_sun_hotspot_graal_HotSpotType, "com/oracle/max/graal/runtime/HotSpotType") \ template(com_sun_hotspot_graal_HotSpotExceptionHandler,"com/oracle/max/graal/runtime/HotSpotExceptionHandler") \ - template(com_sun_hotspot_graal_HotSpotProxy, "com/oracle/max/graal/runtime/HotSpotProxy") \ - template(com_sun_hotspot_graal_Compiler, "com/oracle/max/graal/runtime/Compiler") \ - template(com_sun_hotspot_graal_CompilerImpl, "com/oracle/max/graal/runtime/CompilerImpl") \ + template(com_sun_hotspot_graal_HotSpotProxy, "com/oracle/max/graal/runtime/HotSpotProxy") \ + template(com_sun_hotspot_graal_Compiler, "com/oracle/max/graal/runtime/Compiler") \ + template(com_sun_hotspot_graal_CompilerImpl, "com/oracle/max/graal/runtime/CompilerImpl") \ template(com_sun_cri_ri_RiMethod, "com/sun/cri/ri/RiMethod") \ template(com_sun_cri_ri_RiField, "com/sun/cri/ri/RiField") \ template(com_sun_cri_ri_RiType, "com/sun/cri/ri/RiType") \ @@ -278,7 +278,7 @@ template(com_sun_cri_ri_RiExceptionHandler, "com/sun/cri/ri/RiExceptionHandler") \ template(com_sun_cri_ci_CiAssumptions, "com/sun/cri/ci/CiAssumptions") \ template(com_sun_cri_ci_CiAssumptions_ConcreteSubtype, "com/sun/cri/ci/CiAssumptions$ConcreteSubtype") \ - template(com_sun_cri_ci_CiAssumptions_ConcreteMethod, "com/sun/cri/ci/CiAssumptions$ConcreteMethod") \ + template(com_sun_cri_ci_CiAssumptions_ConcreteMethod, "com/sun/cri/ci/CiAssumptions$ConcreteMethod") \ template(com_sun_cri_ci_CiTargetMethod, "com/sun/cri/ci/CiTargetMethod") \ template(com_sun_cri_ci_CiTargetMethod_Site, "com/sun/cri/ci/CiTargetMethod$Site") \ template(com_sun_cri_ci_CiTargetMethod_Call, "com/sun/cri/ci/CiTargetMethod$Call") \ @@ -295,6 +295,7 @@ template(com_sun_cri_ci_CiRegister, "com/sun/cri/ci/CiRegister") \ template(com_sun_cri_ci_CiCodePos, "com/sun/cri/ci/CiCodePos") \ template(com_sun_cri_ci_CiConstant, "com/sun/cri/ci/CiConstant") \ + template(com_sun_cri_ci_CiVirtualObject, "com/sun/cri/ci/CiVirtualObject") \ template(com_sun_cri_ci_CiKind, "com/sun/cri/ci/CiKind") \ template(com_sun_cri_ci_CiRuntimeCall, "com/sun/cri/ci/CiRuntimeCall") \ template(startCompiler_name, "startCompiler") \ diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Fri Jul 01 18:24:04 2011 +0200 @@ -107,7 +107,7 @@ } // TODO: finish this - graal doesn't provide any scope values at the moment -static ScopeValue* get_hotspot_value(oop value, int frame_size, ScopeValue* &second) { +static ScopeValue* get_hotspot_value(oop value, int frame_size, GrowableArray* objects, ScopeValue* &second) { second = NULL; if (value == CiValue::IllegalValue()) { return new LocationValue(Location::new_stk_loc(Location::invalid, 0)); @@ -182,6 +182,45 @@ return new ConstantLongValue(prim); } tty->print("%i", type); + } else if (value->is_a(CiVirtualObject::klass())) { + oop type = CiVirtualObject::type(value); + int id = CiVirtualObject::id(value); + ciKlass* klass = (ciKlass*) CURRENT_ENV->get_object(java_lang_Class::as_klassOop(HotSpotTypeResolved::javaMirror(type))); + assert(klass->is_instance_klass() || klass->is_array_klass(), "Not supported allocation."); + + for (jint i = 0; i < objects->length(); i++) { + ObjectValue* obj = (ObjectValue*) objects->at(i); + if (obj->id() == id) { + return obj; + } + } + + ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(klass->constant_encoding())); + + arrayOop values = (arrayOop) CiVirtualObject::values(value); + for (jint i = 0; i < values->length(); i++) { + ((oop*) values->base(T_OBJECT))[i]; + } + + for (jint i = 0; i < values->length(); i++) { + ScopeValue* second = NULL; + ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], frame_size, objects, second); + +// if (second != NULL) { +// sv->field_values()->append(second); +// } + sv->field_values()->append(value); + } + +// uint first_ind = spobj->first_index(); +// for (uint i = 0; i < spobj->n_fields(); i++) { +// Node* fld_node = sfn->in(first_ind+i); +// (void)FillLocArray(sv->field_values()->length(), sfn, fld_node, sv->field_values(), objs); +// } +// scval = sv; + + objects->append(sv); + return sv; } else { value->klass()->print(); value->print(); @@ -421,10 +460,10 @@ } -void CodeInstaller::record_scope(jint pc_offset, oop code_pos) { +void CodeInstaller::record_scope(jint pc_offset, oop code_pos, GrowableArray* objects) { oop caller_pos = CiCodePos::caller(code_pos); if (caller_pos != NULL) { - record_scope(pc_offset, caller_pos); + record_scope(pc_offset, caller_pos, objects); } oop frame = NULL; if (code_pos->klass()->klass_part()->name() == vmSymbols::com_sun_cri_ci_CiFrame()) { @@ -466,7 +505,7 @@ for (jint i = 0; i < values->length(); i++) { ScopeValue* second = NULL; - ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], _frame_size, second); + ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], _frame_size, objects, second); if (i < local_count) { if (second != NULL) { @@ -492,6 +531,9 @@ assert(((oop*) values->base(T_OBJECT))[i] == CiValue::IllegalValue(), "double-slot value not followed by CiValue.IllegalValue"); } } + + _debug_recorder->dump_object_pool(objects); + DebugToken* locals_token = _debug_recorder->create_scope_values(locals); DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions); DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors); @@ -516,7 +558,7 @@ _debug_recorder->add_safepoint(pc_offset, create_oop_map(_frame_size, _parameter_count, debug_info)); oop code_pos = CiDebugInfo::codePos(debug_info); - record_scope(pc_offset, code_pos); + record_scope(pc_offset, code_pos, new GrowableArray()); _debug_recorder->end_safepoint(pc_offset); } @@ -537,7 +579,7 @@ if (debug_info != NULL) { _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(_frame_size, _parameter_count, debug_info)); oop code_pos = CiDebugInfo::codePos(debug_info); - record_scope(next_pc_offset, code_pos); + record_scope(next_pc_offset, code_pos, new GrowableArray()); } if (runtime_call != NULL) { diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Fri Jul 01 18:24:04 2011 +0200 @@ -99,7 +99,7 @@ void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site); void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site); - void record_scope(jint pc_offset, oop code_pos); + void record_scope(jint pc_offset, oop code_pos, GrowableArray* objects); void process_exception_handlers(); diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Fri Jul 01 18:24:04 2011 +0200 @@ -144,8 +144,13 @@ } oop GraalCompiler::get_RiField(ciField *field, ciInstanceKlass* accessor_klass, KlassHandle accessor, Bytecodes::Code byteCode, TRAPS) { - bool will_link = field->will_link_from_vm(accessor_klass, byteCode); - int offset = (field->holder()->is_loaded() && will_link) ? field->offset() : -1; + int offset; + if (byteCode != Bytecodes::_illegal) { + bool will_link = field->will_link_from_vm(accessor_klass, byteCode); + offset = (field->holder()->is_loaded() && will_link) ? field->offset() : -1; + } else { + offset = field->offset(); + } Handle field_name = VmIds::toString(field->name()->get_symbol(), CHECK_0); Handle field_holder = get_RiType(field->holder(), accessor, CHECK_0); Handle field_type = get_RiType(field->type(), accessor, CHECK_0); diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Fri Jul 01 18:24:04 2011 +0200 @@ -207,6 +207,11 @@ start_class(CiStackSlot) \ int_field(CiStackSlot, index) \ end_class \ + start_class(CiVirtualObject) \ + int_field(CiVirtualObject, id) \ + oop_field(CiVirtualObject, type, "Lcom/sun/cri/ri/RiType;") \ + oop_field(CiVirtualObject, values, "[Lcom/sun/cri/ci/CiValue;") \ + end_class \ start_class(RiTypeProfile) \ int_field(RiTypeProfile, count) \ int_field(RiTypeProfile, morphism) \ diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/graal/graalVMEntries.cpp --- a/src/share/vm/graal/graalVMEntries.cpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/graal/graalVMEntries.cpp Fri Jul 01 18:24:04 2011 +0200 @@ -631,6 +631,31 @@ return JNIHandles::make_local(THREAD, GraalCompiler::createHotSpotTypeResolved(array, name, THREAD)); } +// public RiField[] RiType_fields(HotSpotTypeResolved klass); +JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_RiType_1fields(JNIEnv *, jobject, jobject klass) { + TRACE_graal_3("VMEntries::RiType_fields"); + KlassHandle klass_handle; + ciInstanceKlass* instance_klass; + objArrayHandle fieldsArray; + HandleMark hm; + { + VM_ENTRY_MARK; + klass_handle = java_lang_Class::as_klassOop(HotSpotTypeResolved::javaMirror(klass)); + instance_klass = (ciInstanceKlass *) CURRENT_ENV->get_object(klass_handle()); + } + GrowableArray* fields = instance_klass->non_static_fields(); + { + VM_ENTRY_MARK; + fieldsArray = oopFactory::new_objArray(SystemDictionary::RiField_klass(), fields->length(), CHECK_NULL); + for (int i = 0; i < fields->length(); i++) { + ciField* field = fields->at(i); + Handle field_handle = GraalCompiler::get_RiField(field, instance_klass, klass_handle, Bytecodes::_illegal, CHECK_NULL); + fieldsArray->obj_at_put(i, field_handle()); + } + } + return JNIHandles::make_local(fieldsArray()); +} + // public RiType getPrimitiveArrayType(CiKind kind); JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_getPrimitiveArrayType(JNIEnv *env, jobject, jobject kind) { TRACE_graal_3("VMEntries::VMEntries_getPrimitiveArrayType"); @@ -847,6 +872,7 @@ {CC"RiType_uniqueConcreteSubtype", CC"("RESOLVED_TYPE")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1uniqueConcreteSubtype)}, {CC"RiType_superType", CC"("RESOLVED_TYPE")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1superType)}, {CC"RiType_arrayOf", CC"("RESOLVED_TYPE")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1arrayOf)}, + {CC"RiType_fields", CC"("RESOLVED_TYPE")["FIELD, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1fields)}, {CC"RiType_isInitialized", CC"("RESOLVED_TYPE")Z", FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1isInitialized)}, {CC"getPrimitiveArrayType", CC"("CI_KIND")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getPrimitiveArrayType)}, {CC"getType", CC"("CLASS")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getType)}, diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Fri Jul 01 18:24:04 2011 +0200 @@ -206,11 +206,11 @@ assert(vf->is_compiled_frame(), "Wrong frame type"); chunk->push(compiledVFrame::cast(vf)); -#ifdef COMPILER2 +//#ifdef COMPILER2 // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. - if (DoEscapeAnalysis) { - if (EliminateAllocations) { +// if (DoEscapeAnalysis) { +// if (EliminateAllocations) { assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames"); GrowableArray* objects = chunk->at(0)->scope()->objects(); @@ -254,8 +254,8 @@ // Restore result. deoptee.set_saved_oop_result(&map, return_value()); } - } - if (EliminateLocks) { +// } +// if (EliminateLocks) { #ifndef PRODUCT bool first = true; #endif @@ -282,9 +282,9 @@ #endif } } - } - } -#endif // COMPILER2 +// } +// } +//#endif // COMPILER2 // Ensure that no safepoint is taken after pointers have been stored // in fields of rematerialized objects. If a safepoint occurs from here on // out the java state residing in the vframeArray will be missed. @@ -709,7 +709,7 @@ } -#ifdef COMPILER2 +//#ifdef COMPILER2 bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS) { Handle pending_exception(thread->pending_exception()); const char* exception_file = thread->exception_file(); @@ -951,7 +951,7 @@ } } #endif -#endif // COMPILER2 +//#endif // COMPILER2 vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk) { diff -r 0affee9ff3a9 -r 5cdaa94cd622 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Fri Jul 01 18:15:05 2011 +0200 +++ b/src/share/vm/runtime/deoptimization.hpp Fri Jul 01 18:24:04 2011 +0200 @@ -109,7 +109,7 @@ // executing in a particular CodeBlob if UseBiasedLocking is enabled static void revoke_biases_of_monitors(CodeBlob* cb); -#ifdef COMPILER2 +//#ifdef COMPILER2 // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); @@ -117,7 +117,7 @@ static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects); static void relock_objects(GrowableArray* monitors, JavaThread* thread); NOT_PRODUCT(static void print_objects(GrowableArray* objects);) -#endif // COMPILER2 +//#endif // COMPILER2 public: static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk);