# HG changeset patch # User Lukas Stadler # Date 1309281762 -7200 # Node ID bee93b329be276aa55c113f9af0acfe0324c814b # Parent 536528f48708d6293c1670764db1963f2a009706# Parent 1ddf16c7271d93ca4d04628e41e316a897a1ad5b merge diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Tue Jun 28 19:22:42 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; @@ -102,6 +107,7 @@ public static boolean TraceAssembler = ____; public static boolean TraceInlining = ____; public static boolean TraceDeadCodeElimination = ____; + public static boolean TraceEscapeAnalysis = ____; public static boolean TraceMemoryMaps = ____; public static boolean TraceReadElimination = ____; public static int TraceBytecodeParserLevel = 0; diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Tue Jun 28 19:22:42 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,33 @@ } } + 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] == current.field() && values[i] == null) { + values[i] = toCiValue(opId, current.input()); + found = true; + break; + } + } + assert found; + current = current.object(); + } while (current != null); + + for (CiValue val : values) { +// assert val != null; + } + + 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 +1975,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 +2008,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 +2294,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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Tue Jun 28 19:22:42 2011 +0200 @@ -402,7 +402,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); } @@ -1610,7 +1610,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()) { @@ -1621,6 +1623,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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Tue Jun 28 19:22:42 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, GraalOptions.TraceInlining).apply(compilation.graph); } Graph graph = compilation.graph; @@ -99,8 +99,13 @@ new CanonicalizerPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); } -// -// new EscapeAnalysisPhase().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.OptLoops) { new LoopPhase().apply(graph); diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Tue Jun 28 19:22:42 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.*; @@ -31,6 +36,7 @@ * The {@code NewInstance} instruction represents the allocation of an instance class object. */ public final class NewInstance extends FloatingNode { + 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 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) { + 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 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Tue Jun 28 19:22:42 2011 +0200 @@ -42,6 +42,7 @@ this.elementType = elementType; } + @Override public CiKind elementKind() { return elementType.kind(); } diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/WriteNode.java diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Tue Jun 28 19:22:42 2011 +0200 @@ -29,6 +29,7 @@ import com.oracle.max.graal.compiler.gen.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; public class DeadCodeEliminationPhase extends Phase { @@ -53,20 +54,29 @@ } } // remove if nodes with constant-value comparison -// for (If ifNode : graph.getNodes(If.class)) { -// Compare compare = ifNode.compare(); -// if (compare.x().isConstant() && compare.y().isConstant()) { -// CiConstant constX = compare.x().asConstant(); -// CiConstant constY = compare.y().asConstant(); -// Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime); -// if (result != null) { -// Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); -// ifNode.replace(actualSuccessor); -// } else { -// TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); -// } -// } -// } + for (If ifNode : graph.getNodes(If.class)) { + BooleanNode bool = ifNode.compare(); + if (bool instanceof Compare) { + Compare compare = (Compare) bool; + if (compare.x().isConstant() && compare.y().isConstant()) { + CiConstant constX = compare.x().asConstant(); + CiConstant constY = compare.y().asConstant(); + Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime); + if (result != null) { + Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); + ifNode.replaceAndDelete(actualSuccessor); + } else { + TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); + } + } + } + } + // remove unnecessary FixedGuards + for (FixedGuard guard : graph.getNodes(FixedGuard.class)) { + if (guard.node() instanceof IsNonNull && ((IsNonNull) guard.node()).object() instanceof NewInstance) { + guard.replaceAndDelete(guard.next()); + } + } flood.add(graph.start()); diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 19:22:42 2011 +0200 @@ -0,0 +1,381 @@ +/* + * 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(); + for (int i = 0; i < predecessors.size(); i++) { + BlockExitState exitState = exitStates.get(predecessors.get(i)); + if (exitState == null) { + mergedFields.addAll(fields.values()); + 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, GraalOptions.TraceInlining).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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Tue Jun 28 19:22:42 2011 +0200 @@ -963,7 +963,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); diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Tue Jun 28 19:22:42 2011 +0200 @@ -32,25 +32,29 @@ 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 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 final Map parentMethod = new HashMap(); private int inliningSize; private final boolean trace; + private final Collection hints; - public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) { + public InliningPhase(GraalCompilation compilation, IR ir, Collection hints, boolean trace) { this.compilation = compilation; this.ir = ir; + this.hints = hints; this.trace = trace; } @@ -60,59 +64,33 @@ inliningSize += method.codeSize(); } - public static HashMap methodCount = new HashMap(); + private Queue newInvokes = new ArrayDeque(); + private Graph graph; + @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); + newInvokes.add(invoke); + } + } + + for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { + Queue queue = newInvokes; + newInvokes = new ArrayDeque(); + for (Invoke invoke : queue) { + if (!invoke.isDeleted()) { + inlineInvoke(invoke, iterations, ratio); + if (inliningSize > GraalOptions.MaximumInstructionCount) { + break; } - } 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); - } - } 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(graph); - guard.setNode(isType); - 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); - } - } - } - } - if (inliningSize > GraalOptions.MaximumInstructionCount) { - break; } } @@ -157,16 +135,65 @@ } } + private void inlineInvoke(Invoke invoke, int iterations, float ratio) { + RiMethod parent = invoke.stateAfter().method(); + RiTypeProfile profile = parent.typeProfile(invoke.bci); + if (!checkInvokeConditions(invoke)) { + return; + } + if (invoke.opcode() == Bytecodes.INVOKESPECIAL || 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); + } + } 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(graph); + guard.setNode(isType); + 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); + } + } else { + if (trace) { + TTY.println("not inlining %s because GraalOptions.InlineWithTypeCheck is false", methodName(invoke.target, invoke)); + } + } + } else { + if (trace) { + TTY.println("not inlining %s because no monomorphic receiver could be found", methodName(invoke.target, invoke)); + } + } + } + } + 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)"; @@ -241,7 +268,11 @@ } private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) { - if (method.codeSize() > GraalOptions.MaximumInlineSize) { + int maximumSize = GraalOptions.MaximumInlineSize; + if (hints != null && hints.contains(invoke)) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } + if (method.codeSize() > maximumSize) { if (trace) { TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize); } @@ -254,10 +285,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; @@ -265,6 +293,9 @@ maximumSize = GraalOptions.MaximumInlineSize; } } + if (hints != null && hints.contains(invoke)) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } if (method.codeSize() > maximumSize) { if (trace) { 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); @@ -359,7 +390,7 @@ for (Node node : duplicates.values()) { if (node instanceof Invoke) { - parentMethod.put((Invoke) node, method); + newInvokes.add((Invoke) node); } } diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Tue Jun 28 19:22:42 2011 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; @@ -182,4 +183,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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Tue Jun 28 19:22:42 2011 +0200 @@ -121,6 +121,10 @@ return rethrowException; } + public RiMethod method() { + return method; + } + /** * Gets a copy of this frame state. */ diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java Tue Jun 28 19:22:42 2011 +0200 @@ -150,4 +150,8 @@ return null; } + @Override + public RiField[] fields() { + return null; + } } diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java Tue Jun 28 19:22:42 2011 +0200 @@ -222,4 +222,8 @@ return ((HotSpotMethodResolved) method).uniqueConcreteMethod(); } + @Override + public RiField[] fields() { + return compiler.getVMEntries().RiType_fields(this); + } } diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java Tue Jun 28 19:22:42 2011 +0200 @@ -201,4 +201,8 @@ throw unresolved("uniqueConcreteMethod"); } + @Override + public RiField[] fields() { + return null; + } } diff -r 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 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 Tue Jun 28 17:17:51 2011 +0200 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java Tue Jun 28 19:22:42 2011 +0200 @@ -141,5 +141,8 @@ return getType(o.getClass()); } + @Override + public native RiField[] RiType_fields(HotSpotTypeResolved klass); + // Checkstyle: resume } diff -r 1ddf16c7271d -r bee93b329be2 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/graal/graalVMEntries.cpp --- a/src/share/vm/graal/graalVMEntries.cpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/graal/graalVMEntries.cpp Tue Jun 28 19:22:42 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; + { + 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(); + + objArrayHandle fieldsArray; + { + 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 1ddf16c7271d -r bee93b329be2 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Tue Jun 28 19:22:42 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 1ddf16c7271d -r bee93b329be2 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Tue Jun 28 17:17:51 2011 +0200 +++ b/src/share/vm/runtime/deoptimization.hpp Tue Jun 28 19:22:42 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);