# HG changeset patch # User Lukas Stadler # Date 1306938377 -7200 # Node ID 7596ae867a7bc654341020822ed3d4bd599537a0 # Parent 633e66de40fe0e9da9f5a97270090b959d993069 basic inlining passes all tests, including optimistic inlining diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java --- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java Wed Jun 01 16:26:17 2011 +0200 @@ -96,7 +96,7 @@ this.method = method; this.stats = stats == null ? new CiStatistics() : stats; this.registerConfig = method == null ? compiler.globalStubRegisterConfig : runtime.getRegisterConfig(method); - this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(0, 0, 0, 0, graph) : null; + this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(method, 0, 0, 0, 0, graph) : null; if (compiler.isObserved()) { compiler.fireCompilationStarted(new CompilationEvent(this)); diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java --- a/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java Wed Jun 01 16:26:17 2011 +0200 @@ -90,6 +90,7 @@ public static boolean TraceRelocation = ____; public static boolean TraceLIRVisit = ____; public static boolean TraceAssembler = ____; + public static boolean TraceInlining = ____; public static int TraceBytecodeParserLevel = 0; public static boolean QuietBailout = ____; diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java --- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java Wed Jun 01 16:26:17 2011 +0200 @@ -1884,7 +1884,7 @@ } } - CiFrame computeFrameForState(int opId, FrameState state, CiBitMap frameRefMap) { + CiFrame computeFrameForState(FrameState state, int opId, CiBitMap frameRefMap) { CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; int valueIndex = 0; @@ -1909,8 +1909,11 @@ } } } - - return new CiFrame(null, ir.compilation.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize()); + CiFrame caller = null; + if (state.outerFrameState() != null) { + caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap); + } + return new CiFrame(caller, state.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize()); } private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) { @@ -1946,7 +1949,7 @@ if (C1XOptions.TraceLinearScanLevel >= 3) { TTY.println("creating debug information at opId %d", opId); } - return computeFrameForState(opId, state, frameRefMap); + return computeFrameForState(state, opId, frameRefMap); } private void assignLocations(List instructions, IntervalWalker iw) { diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java --- a/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java Wed Jun 01 16:26:17 2011 +0200 @@ -300,7 +300,7 @@ if (Modifier.isSynchronized(compilation.method.accessFlags())) { bci = Instruction.SYNCHRONIZATION_ENTRY_BCI; } - FrameState fs = new FrameState(bci, compilation.method.maxLocals(), 0, 0, compilation.graph); + FrameState fs = new FrameState(compilation.method, bci, compilation.method.maxLocals(), 0, 0, compilation.graph); for (Node node : compilation.graph.start().usages()) { if (node instanceof Local) { Local local = (Local) node; diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java --- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java Wed Jun 01 16:26:17 2011 +0200 @@ -61,24 +61,30 @@ */ public static final int TRACELEVEL_STATE = 2; - private final IR ir; private final C1XCompilation compilation; + private final CompilerGraph graph; + private final CiStatistics stats; + private final RiRuntime runtime; + private final RiMethod method; + private final RiConstantPool constantPool; private final BytecodeStream stream; // the bytecode stream + private final LogStream log; + private final FrameStateBuilder frameState; // the current execution state + // bci-to-block mapping private Block[] blockFromBci; private ArrayList blockList; - private Block syncBlock; + private int nextBlockNumber; + + private Value methodSynchronizedObject; private CiExceptionHandler syncHandler; private Block unwindBlock; private Block returnBlock; - // the constant pool - private final RiConstantPool constantPool; - // the worklist of blocks, sorted by depth first number private final PriorityQueue workList = new PriorityQueue(10, new Comparator() { public int compare(Block o1, Block o2) { @@ -86,14 +92,11 @@ } }); - private FrameStateBuilder frameState; // the current execution state private Instruction lastInstr; // the last instruction added - private final LogStream log; + private final Set blocksOnWorklist = new HashSet(); + private final Set blocksVisited = new HashSet(); - private Value rootMethodSynchronizedObject; - - private final CompilerGraph graph; /** * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. @@ -102,15 +105,18 @@ * @param ir the IR to build the graph into * @param graph */ - public GraphBuilder(C1XCompilation compilation, IR ir, CompilerGraph graph) { + public GraphBuilder(C1XCompilation compilation, RiMethod method, CompilerGraph graph) { this.compilation = compilation; - this.ir = ir; + this.graph = graph; + + this.runtime = compilation.runtime; + this.method = method; this.stats = compilation.stats; - log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; - stream = new BytecodeStream(compilation.method.code()); - constantPool = compilation.runtime.getConstantPool(compilation.method); - this.graph = graph; - this.frameState = new FrameStateBuilder(compilation.method, graph); + this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; + this.stream = new BytecodeStream(method.code()); + + this.constantPool = runtime.getConstantPool(method); + this.frameState = new FrameStateBuilder(method, graph); } /** @@ -118,20 +124,18 @@ * @param scope the top IRScope */ public void build() { - RiMethod rootMethod = compilation.method; - if (log != null) { log.println(); - log.println("Compiling " + compilation.method); + log.println("Compiling " + method); } // 2. compute the block map, setup exception handlers and get the entrypoint(s) - BlockMap blockMap = compilation.getBlockMap(rootMethod); + BlockMap blockMap = compilation.getBlockMap(method); blockList = new ArrayList(blockMap.blocks); - blockFromBci = new Block[rootMethod.code().length]; + blockFromBci = new Block[method.code().length]; for (int i = 0; i < blockList.size(); i++) { - int blockID = ir.nextBlockNumber(); + int blockID = nextBlockNumber(); assert blockID == i; Block block = blockList.get(i); if (block.startBci >= 0) { @@ -145,15 +149,15 @@ lastInstr = createTarget(startBlock, frameState); graph.start().setStart(lastInstr); - if (isSynchronized(rootMethod.accessFlags())) { + if (isSynchronized(method.accessFlags())) { // 4A.1 add a monitor enter to the start block - rootMethodSynchronizedObject = synchronizedObject(frameState, compilation.method); - genMonitorEnter(rootMethodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI); + methodSynchronizedObject = synchronizedObject(frameState, method); + genMonitorEnter(methodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI); // 4A.2 finish the start block finishStartBlock(startBlock); // 4A.3 setup an exception handler to unlock the root method synchronized object - syncHandler = new CiExceptionHandler(0, rootMethod.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); + syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); } else { // 4B.1 simply finish the start block finishStartBlock(startBlock); @@ -165,6 +169,7 @@ addToWorkList(blockFromBci[0]); iterateAllBlocks(); + // remove Placeholders for (Node n : graph.getNodes()) { if (n instanceof Placeholder) { Placeholder p = (Placeholder) n; @@ -176,21 +181,13 @@ } } - for (Node n : graph.getNodes()) { - assert !(n instanceof Placeholder); - } - - + // remove FrameStates for (Node n : graph.getNodes()) { if (n instanceof FrameState) { boolean delete = false; if (n.usages().size() == 0 && n.predecessors().size() == 0) { delete = true; } -// if (n.predecessors().size() == 0 && n.usages().size() == 1 && n.usages().get(0) instanceof BlockBegin) { -// n.usages().get(0).inputs().replace(n, null); -// delete = true; -// } if (delete) { n.delete(); } @@ -198,11 +195,16 @@ } } + private int nextBlockNumber() { + stats.blockCount++; + return nextBlockNumber++; + } + private Block nextBlock(int bci) { Block block = new Block(); block.startBci = bci; block.endBci = bci; - block.blockID = ir.nextBlockNumber(); + block.blockID = nextBlockNumber(); return block; } @@ -211,7 +213,7 @@ unwindBlock = new Block(); unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - unwindBlock.blockID = ir.nextBlockNumber(); + unwindBlock.blockID = nextBlockNumber(); addToWorkList(unwindBlock); } return unwindBlock; @@ -222,15 +224,12 @@ returnBlock = new Block(); returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - returnBlock.blockID = ir.nextBlockNumber(); + returnBlock.blockID = nextBlockNumber(); addToWorkList(returnBlock); } return returnBlock; } - - private Set blocksOnWorklist = new HashSet(); - private void markOnWorkList(Block block) { blocksOnWorklist.add(block); } @@ -239,8 +238,6 @@ return blocksOnWorklist.contains(block); } - private Set blocksVisited = new HashSet(); - private void markVisited(Block block) { blocksVisited.add(block); } @@ -328,10 +325,6 @@ } } - public RiMethod method() { - return compilation.method; - } - public BytecodeStream stream() { return stream; } @@ -360,7 +353,7 @@ assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; RiExceptionHandler firstHandler = null; - RiExceptionHandler[] exceptionHandlers = compilation.method.exceptionHandlers(); + RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); // join with all potential exception handlers if (exceptionHandlers != null) { for (RiExceptionHandler handler : exceptionHandlers) { @@ -422,7 +415,7 @@ } private void genLoadConstant(int cpi) { - Object con = constantPool().lookupConstant(cpi); + Object con = constantPool.lookupConstant(cpi); if (con instanceof RiType) { // this is a load of class constant which might be unresolved @@ -550,7 +543,7 @@ private void genArithmeticOp(CiKind result, int opcode, CiKind x, CiKind y, boolean canTrap) { Value yValue = frameState.pop(y); Value xValue = frameState.pop(x); - Value result1 = append(new ArithmeticOp(opcode, result, xValue, yValue, isStrict(method().accessFlags()), canTrap, graph)); + Value result1 = append(new ArithmeticOp(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph)); frameState.push(result, result1); } @@ -589,7 +582,7 @@ int delta = stream().readIncrement(); Value x = frameState.localAt(index); Value y = append(Constant.forInt(delta, graph)); - frameState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method().accessFlags()), false, graph))); + frameState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method.accessFlags()), false, graph))); } private void genGoto(int fromBCI, int toBCI) { @@ -641,7 +634,7 @@ private void genCheckCast() { int cpi = stream().readCPI(); - RiType type = constantPool().lookupType(cpi, CHECKCAST); + RiType type = constantPool.lookupType(cpi, CHECKCAST); boolean isInitialized = type.isResolved(); Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); Value object = frameState.apop(); @@ -654,7 +647,7 @@ private void genInstanceOf() { int cpi = stream().readCPI(); - RiType type = constantPool().lookupType(cpi, INSTANCEOF); + RiType type = constantPool.lookupType(cpi, INSTANCEOF); boolean isInitialized = type.isResolved(); Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); Value object = frameState.apop(); @@ -666,9 +659,9 @@ } void genNewInstance(int cpi) { - RiType type = constantPool().lookupType(cpi, NEW); + RiType type = constantPool.lookupType(cpi, NEW); if (type.isResolved()) { - NewInstance n = new NewInstance(type, cpi, constantPool(), graph); + NewInstance n = new NewInstance(type, cpi, constantPool, graph); frameState.apush(append(n)); } else { append(new Deoptimize(graph)); @@ -678,13 +671,13 @@ private void genNewTypeArray(int typeCode) { CiKind kind = CiKind.fromArrayTypeCode(typeCode); - RiType elementType = compilation.runtime.asRiType(kind); + RiType elementType = runtime.asRiType(kind); NewTypeArray nta = new NewTypeArray(frameState.ipop(), elementType, graph); frameState.apush(append(nta)); } private void genNewObjectArray(int cpi) { - RiType type = constantPool().lookupType(cpi, ANEWARRAY); + RiType type = constantPool.lookupType(cpi, ANEWARRAY); Value length = frameState.ipop(); if (type.isResolved()) { NewArray n = new NewObjectArray(type, length, graph); @@ -697,14 +690,14 @@ } private void genNewMultiArray(int cpi) { - RiType type = constantPool().lookupType(cpi, MULTIANEWARRAY); + RiType type = constantPool.lookupType(cpi, MULTIANEWARRAY); int rank = stream().readUByte(bci() + 3); Value[] dims = new Value[rank]; for (int i = rank - 1; i >= 0; i--) { dims[i] = frameState.ipop(); } if (type.isResolved()) { - NewArray n = new NewMultiArray(type, dims, cpi, constantPool(), graph); + NewArray n = new NewMultiArray(type, dims, cpi, constantPool, graph); frameState.apush(append(n)); } else { append(new Deoptimize(graph)); @@ -853,7 +846,7 @@ private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { CiKind resultType = returnKind(target); - Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(compilation.method.holder()), 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); @@ -865,7 +858,7 @@ exact = receiver.exactType(); if (exact == null) { if (receiver.isConstant()) { - exact = compilation.runtime.getTypeOf(receiver.asConstant()); + exact = runtime.getTypeOf(receiver.asConstant()); } if (exact == null) { RiType declared = receiver.declaredType(); @@ -886,7 +879,7 @@ } if (exactType == null && receiver instanceof Local && ((Local) receiver).index() == 0) { // the exact type isn't known, but the receiver is parameter 0 => use holder - receiverType = compilation.method.holder(); + receiverType = method.holder(); exactType = receiverType.exactType(); } boolean needsCheck = true; @@ -926,13 +919,13 @@ private void genMonitorEnter(Value x, int bci) { int lockNumber = frameState.locksSize(); MonitorAddress lockAddress = null; - if (compilation.runtime.sizeOfBasicObjectLock() != 0) { + if (runtime.sizeOfBasicObjectLock() != 0) { lockAddress = new MonitorAddress(lockNumber, graph); append(lockAddress); } MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); appendWithBCI(monitorEnter); - frameState.lock(ir, x, lockNumber + 1); + frameState.lock(x); if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { monitorEnter.setStateAfter(frameState.create(0)); } @@ -944,7 +937,7 @@ throw new CiBailout("monitor stack underflow"); } MonitorAddress lockAddress = null; - if (compilation.runtime.sizeOfBasicObjectLock() != 0) { + if (runtime.sizeOfBasicObjectLock() != 0) { lockAddress = new MonitorAddress(lockNumber, graph); append(lockAddress); } @@ -1130,22 +1123,22 @@ } private void createUnwindBlock(Block block) { - if (Modifier.isSynchronized(method().accessFlags())) { - genMonitorExit(rootMethodSynchronizedObject); + if (Modifier.isSynchronized(method.accessFlags())) { + genMonitorExit(methodSynchronizedObject); } append(graph.createUnwind(frameState.apop())); } private void createReturnBlock(Block block) { - if (method().isConstructor() && method().holder().superType() == null) { + if (method.isConstructor() && method.holder().superType() == null) { callRegisterFinalizer(); } - CiKind returnKind = method().signature().returnKind().stackKind(); + CiKind returnKind = method.signature().returnKind().stackKind(); Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind); assert frameState.stackSize() == 0; - if (Modifier.isSynchronized(method().accessFlags())) { - genMonitorExit(rootMethodSynchronizedObject); + if (Modifier.isSynchronized(method.accessFlags())) { + genMonitorExit(methodSynchronizedObject); } append(graph.createReturn(x)); } @@ -1218,7 +1211,7 @@ private void traceState() { if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) { - log.println(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method())); + log.println(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); for (int i = 0; i < frameState.localsSize(); ++i) { Value value = frameState.localAt(i); log.println(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); @@ -1417,14 +1410,14 @@ case DRETURN : genReturn(frameState.dpop()); break; case ARETURN : genReturn(frameState.apop()); break; case RETURN : genReturn(null ); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, constantPool().lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, constantPool().lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, constantPool().lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, constantPool().lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(constantPool().lookupMethod(cpi, opcode), null, cpi, constantPool()); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, constantPool.lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, constantPool.lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, constantPool.lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, constantPool.lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(constantPool.lookupMethod(cpi, opcode), null, cpi, constantPool); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; case NEW : genNewInstance(stream.readCPI()); break; case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; @@ -1468,10 +1461,6 @@ frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); } - private RiConstantPool constantPool() { - return constantPool; - } - /** * Adds a block to the worklist, if it is not already in the worklist. * This method will keep the worklist topologically stored (i.e. the lower diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/graph/IR.java --- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java Wed Jun 01 16:26:17 2011 +0200 @@ -22,6 +22,7 @@ */ package com.sun.c1x.graph; +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.graph.*; @@ -33,6 +34,8 @@ import com.sun.c1x.lir.*; import com.sun.c1x.observer.*; import com.sun.c1x.value.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; /** * This class implements the overall container for the HIR (high-level IR) graph @@ -161,12 +164,227 @@ private void buildGraph() { // Graph builder must set the startBlock and the osrEntryBlock - new GraphBuilder(compilation, this, compilation.graph).build(); + new GraphBuilder(compilation, compilation.method, compilation.graph).build(); verifyAndPrint("After graph building"); + List trivialInline = new ArrayList(); + List deoptInline = new ArrayList(); + List deoptMethods = new ArrayList(); + for (Node node : compilation.graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + RiMethod target = invoke.target; + if (target.isResolved() && !Modifier.isNative(target.accessFlags())) { + if (target.canBeStaticallyBound()) { + trivialInline.add(invoke); + } else { + RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); + if (concrete != null) { + deoptInline.add(invoke); + deoptMethods.add(concrete); + } + } + } + } + } + + int allowedInlinings = 50; + for (Invoke invoke : trivialInline) { + if (inlineMethod(invoke, invoke.target)) { + if (--allowedInlinings <= 0) { + break; + } + } + } + + for (int i = 0; i < deoptInline.size(); i++) { + Invoke invoke = deoptInline.get(i); + RiMethod method = deoptMethods.get(i); + if (inlineMethod(invoke, method)) { + if (C1XOptions.TraceInlining) { + System.out.println("registering concrete method assumption..."); + } + compilation.assumptions.recordConcreteMethod(invoke.target, method); + if (--allowedInlinings <= 0) { + break; + } + } + } + if (C1XOptions.PrintCompilation) { - TTY.print(String.format("%3d blocks | ", this.numberOfBlocks())); + TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); + } + } + + private boolean inlineMethod(Invoke invoke, RiMethod method) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + + if (method.code().length > 50) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of code size"); + } + return false; + } + + Instruction exceptionEdge = invoke.exceptionEdge(); + if (exceptionEdge != null) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of exceptionEdge"); + } + return false; + } + if (!method.holder().isInitialized()) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of non-initialized class"); + } + return false; + } + + if (C1XOptions.TraceInlining) { + System.out.println("building graph: " + name); + } + CompilerGraph graph = new CompilerGraph(); + new GraphBuilder(compilation, method, graph).build(); + + boolean withReceiver = !Modifier.isStatic(method.accessFlags()); + + int argumentCount = method.signature().argumentCount(false); + Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; + int slot = withReceiver ? 1 : 0; + int param = withReceiver ? 1 : 0; + for (int i = 0; i < argumentCount; i++) { + parameters[param++] = invoke.argument(slot); + slot += method.signature().argumentKindAt(i).sizeInSlots(); + } + if (withReceiver) { + parameters[0] = invoke.argument(0); + } + + HashMap replacements = new HashMap(); + ArrayList nodes = new ArrayList(); + ArrayList frameStates = new ArrayList(); + Return returnNode = null; + Unwind unwindNode = null; + StartNode startNode = null; + boolean invokes = false; + for (Node node : graph.getNodes()) { + if (node != null) { + if (node instanceof StartNode) { + startNode = (StartNode) node; + } else if (node instanceof Local) { + replacements.put(node, parameters[((Local) node).index()]); + } else { + nodes.add(node); + if (node instanceof Return) { + returnNode = (Return) node; + } else if (node instanceof Unwind) { + unwindNode = (Unwind) node; + } else if (node instanceof FrameState) { + frameStates.add(node); + } + } + } + } + if (unwindNode != null) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of unwind node"); + } + return false; + } + if (invokes) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of invokes"); + } + return false; + } + + if (C1XOptions.TraceInlining) { + System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); + } + + Instruction pred; + if (withReceiver) { + pred = new NullCheck(parameters[0], compilation.graph); + } else { + pred = new Merge(compilation.graph); + } + assert invoke.predecessors().size() == 1; + invoke.predecessors().get(0).successors().replace(invoke, pred); + replacements.put(startNode, pred); + + Map duplicates = compilation.graph.addDuplicate(nodes, replacements); + + if (returnNode != null) { + List usages = new ArrayList(invoke.usages()); + for (Node usage : usages) { + if (returnNode.result() instanceof Local) { + usage.inputs().replace(invoke, replacements.get(returnNode.result())); + } else { + usage.inputs().replace(invoke, duplicates.get(returnNode.result())); + } + } + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.inputs().clearAll(); + + assert returnDuplicate.predecessors().size() == 1; + Node returnPred = returnDuplicate.predecessors().get(0); + int index = returnDuplicate.predecessorsIndex().get(0); + returnPred.successors().setAndClear(index, invoke, 0); + + returnDuplicate.delete(); + } + FrameState stateAfter = invoke.stateAfter(); + if (frameStates.size() > 0) { + FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); + for (Node frameState : frameStates) { + ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); + } + } + + invoke.successors().clearAll(); + invoke.inputs().clearAll(); + invoke.delete(); + + stateAfter.delete(); + + deleteUnused(exceptionEdge); + + verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); + return true; + } + + private void deleteUnused(Node node) { + if (node != null && node.predecessors().size() == 0) { + if (node instanceof ExceptionObject) { + Node successor = node.successors().get(0); + node.successors().clearAll(); + if (successor instanceof ExceptionDispatch) { + ExceptionDispatch dispatch = (ExceptionDispatch) successor; + Node succ1 = dispatch.catchSuccessor(); + Node succ2 = dispatch.otherSuccessor(); + if (succ1 instanceof Merge) { + ((Merge) succ1).removePhiPredecessor(dispatch); + } + if (succ2 instanceof Merge) { + ((Merge) succ2).removePhiPredecessor(dispatch); + } + dispatch.successors().clearAll(); + deleteUnused(succ1); + deleteUnused(succ2); + dispatch.delete(); + } else { + assert successor instanceof Merge; + System.out.println("succ: " + successor.successors().get(0)); + Node next = successor.successors().get(0); + successor.successors().clearAll(); + deleteUnused(next); + successor.delete(); + } + node.delete(); + } else if (node instanceof Unwind) { + node.delete(); + } } } @@ -202,15 +420,6 @@ } } - - public int nextBlockNumber() { - return compilation.stats.blockCount++; - } - - public int numberOfBlocks() { - return compilation.stats.blockCount; - } - public int numLoops() { return compilation.stats.loopCount; } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java --- a/graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java Wed Jun 01 16:26:17 2011 +0200 @@ -58,6 +58,11 @@ } @Override + public String shortName() { + return "LoopBegin"; + } + + @Override public Node copy(Graph into) { LoopBegin x = new LoopBegin(into); x.setNonNull(isNonNull()); diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java --- a/graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java Wed Jun 01 16:26:17 2011 +0200 @@ -69,6 +69,11 @@ } @Override + public String shortName() { + return "LoopEnd"; + } + + @Override public Node copy(Graph into) { LoopEnd x = new LoopEnd(into); x.setNonNull(isNonNull()); diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java --- a/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java Wed Jun 01 16:26:17 2011 +0200 @@ -267,4 +267,17 @@ x.setNonNull(isNonNull()); return x; } + + public void removePhiPredecessor(ExceptionDispatch successor) { + int predIndex = predecessors().indexOf(successor); + assert predIndex != -1; + + for (Node usage : usages()) { + if (usage instanceof Phi) { + Phi phi = (Phi) usage; + assert phi.valueCount() == predecessors().size(); + phi.removeInput(predIndex + 1); + } + } + } } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java --- a/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java Wed Jun 01 16:26:17 2011 +0200 @@ -131,15 +131,11 @@ @Override public String shortName() { StringBuilder str = new StringBuilder(); - for (int i = 1; i < inputs().size(); ++i) { - if (i != 1) { + for (int i = 0; i < valueCount(); ++i) { + if (i != 0) { str.append(' '); } - if (inputs().get(i) != null) { - str.append(inputs().get(i).id()); - } else { - str.append("-"); - } + str.append(valueAt(i) == null ? "-" : valueAt(i).id()); } return "Phi: (" + str + ")"; } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java --- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java Wed Jun 01 16:26:17 2011 +0200 @@ -31,6 +31,7 @@ import com.sun.c1x.debug.*; import com.sun.c1x.ir.*; import com.sun.cri.ci.*; +import com.sun.cri.ri.*; /** * The {@code FrameState} class encapsulates the frame state (i.e. local variables and @@ -60,13 +61,12 @@ return super.successorCount() + SUCCESSOR_COUNT; } - public Value outerFrameState() { - return (Value) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE); + public FrameState outerFrameState() { + return (FrameState) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE); } - public Value setOuterFrameState(Value n) { - assert n == null || n.kind == CiKind.Object; - return (Value) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n); + public FrameState setOuterFrameState(FrameState n) { + return (FrameState) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n); } @Override @@ -80,6 +80,8 @@ */ public final int bci; + public final RiMethod method; + /** * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables. * @@ -88,8 +90,9 @@ * @param stackSize size of the stack * @param lockSize number of locks */ - public FrameState(int bci, int localsSize, int stackSize, int locksSize, Graph graph) { + public FrameState(RiMethod method, int bci, int localsSize, int stackSize, int locksSize, Graph graph) { super(CiKind.Illegal, localsSize + stackSize + locksSize + INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.method = method; this.bci = bci; this.localsSize = localsSize; this.stackSize = stackSize; @@ -98,8 +101,8 @@ C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize; } - FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList locks, Graph graph) { - this(bci, locals.length, stackSize, locks.size(), graph); + FrameState(RiMethod method, int bci, Value[] locals, Value[] stack, int stackSize, ArrayList locks, Graph graph) { + this(method, bci, locals.length, stackSize, locks.size(), graph); for (int i = 0; i < locals.length; i++) { setValueAt(i, locals[i]); } @@ -125,7 +128,7 @@ */ @Override public FrameState duplicateWithEmptyStack(int bci) { - FrameState other = new FrameState(bci, localsSize, 0, locksSize(), graph()); + FrameState other = new FrameState(method, bci, localsSize, 0, locksSize(), graph()); for (int i = 0; i < localsSize; i++) { other.setValueAt(i, localAt(i)); } @@ -144,7 +147,7 @@ public FrameState duplicateModified(int bci, CiKind popKind, Value... pushedValues) { int popSlots = popKind.sizeInSlots(); int pushSlots = pushedValues.length; - FrameState other = new FrameState(bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph()); + FrameState other = new FrameState(method, bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph()); for (int i = 0; i < localsSize; i++) { other.setValueAt(i, localAt(i)); } @@ -403,11 +406,9 @@ } public Merge block() { - if (usages().size() > 0) { - assert usages().size() == 1; - Node node = usages().get(0); - if (node instanceof Merge) { - return (Merge) node; + for (Node usage : usages()) { + if (usage instanceof Merge) { + return (Merge) usage; } } return null; @@ -453,6 +454,9 @@ proc.doValue(value); } } + if (outerFrameState() != null) { + outerFrameState().forEachLiveStateValue(proc); + } } @Override @@ -487,12 +491,12 @@ @Override public FrameState copy() { - return new FrameState(bci, localsSize, stackSize, locksSize, graph()); + return new FrameState(method, bci, localsSize, stackSize, locksSize, graph()); } private FrameState copy(int newBci) { - return new FrameState(newBci, localsSize, stackSize, locksSize, graph()); + return new FrameState(method, newBci, localsSize, stackSize, locksSize, graph()); } @Override @@ -506,7 +510,7 @@ @Override public Node copy(Graph into) { - FrameState x = new FrameState(bci, localsSize, stackSize, locksSize, into); + FrameState x = new FrameState(method, bci, localsSize, stackSize, locksSize, into); x.setNonNull(isNonNull()); return x; } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java --- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java Wed Jun 01 16:26:17 2011 +0200 @@ -28,7 +28,6 @@ import java.util.*; import com.oracle.graal.graph.*; -import com.sun.c1x.graph.*; import com.sun.c1x.ir.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -44,7 +43,10 @@ private int stackIndex; + private final RiMethod method; + public FrameStateBuilder(RiMethod method, Graph graph) { + this.method = method; this.graph = graph; this.locals = new Value[method.maxLocals()]; this.stack = new Value[method.maxStackSize()]; @@ -97,12 +99,12 @@ } public FrameState create(int bci) { - return new FrameState(bci, locals, stack, stackIndex, locks, graph); + return new FrameState(method, bci, locals, stack, stackIndex, locks, graph); } @Override public FrameState duplicateWithEmptyStack(int bci) { - FrameState frameState = new FrameState(bci, locals, new Value[0], 0, locks, graph); + FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, graph); frameState.setOuterFrameState(outerFrameState()); return frameState; } @@ -361,7 +363,7 @@ * @param scope the IRScope in which this locking operation occurs * @param obj the object being locked */ - public void lock(IR ir, Value obj, int totalNumberOfLocks) { + public void lock(Value obj) { locks.add(obj); } @@ -498,7 +500,7 @@ } @Override - public Value outerFrameState() { + public FrameState outerFrameState() { return null; } } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalGraph/src/com/oracle/graal/graph/Graph.java --- a/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java Wed Jun 01 16:26:17 2011 +0200 @@ -67,7 +67,7 @@ return new NodeMap(this); } - public void addDuplicate(Collection nodes, Map replacements) { + public Map addDuplicate(Collection nodes, Map replacements) { Map newNodes = new HashMap(); // create node duplicates for (Node node : nodes) { @@ -125,5 +125,6 @@ } } } + return newNodes; } } diff -r 633e66de40fe -r 7596ae867a7b graal/GraalGraph/src/com/oracle/graal/graph/Node.java --- a/graal/GraalGraph/src/com/oracle/graal/graph/Node.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalGraph/src/com/oracle/graal/graph/Node.java Wed Jun 01 16:26:17 2011 +0200 @@ -118,7 +118,7 @@ public void delete() { assert !isDeleted(); - assert usages.size() == 0 && predecessors.size() == 0; + assert usages.size() == 0 && predecessors.size() == 0 : "usages: " + usages.size() + ", predecessors: " + predecessors().size(); assert predecessorsIndex.size() == 0; for (int i = 0; i < inputs.size(); ++i) { inputs.set(i, Null); diff -r 633e66de40fe -r 7596ae867a7b graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java --- a/graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java Tue May 31 16:54:15 2011 +0200 +++ b/graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java Wed Jun 01 16:26:17 2011 +0200 @@ -127,8 +127,10 @@ if (value.predecessors.get(i) == clearedNode && value.predecessorsIndex.get(i) == clearedIndex) { value.predecessors.set(i, self()); value.predecessorsIndex.set(i, index); + return; } } + assert false; } public int size() {