# HG changeset patch # User Lukas Stadler # Date 1307531205 -7200 # Node ID 693e4e92346b912db24d9ebe4f5ba5eb6fbda75f # Parent adfc15cbcabcbca1b5bf55a4b9a77a57a577d7f1# Parent 971b7dcf64dc1e883ce4ad7b8a4e0bcf3555eb9d merge diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XOptions.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XOptions.java Wed Jun 08 13:06:45 2011 +0200 @@ -62,7 +62,6 @@ public static String PrintFilter = null; // printing settings - public static boolean PrintHIR = ____; public static boolean PrintLIR = ____; public static boolean PrintCFGToFile = ____; diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/DeadCodeElimination.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/DeadCodeElimination.java Wed Jun 08 13:04:17 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * 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.graph; - -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.ir.*; -import com.oracle.max.graal.graph.*; - - -public class DeadCodeElimination extends Phase { - - private NodeBitMap alive; - private NodeWorklist worklist; - private Graph graph; - - public int deletedNodeCount; - - @Override - protected void run(Graph graph) { - this.graph = graph; - this.alive = graph.createNodeBitMap(); - this.worklist = graph.createNodeWorklist(); - - worklist.add(graph.start()); - - iterateSuccessors(); - disconnectCFGNodes(); - - iterateInputs(); - disconnectNonCFGNodes(); - - deleteCFGNodes(); - deleteNonCFGNodes(); - - new PhiSimplifier(graph); - - if (C1XOptions.TraceDeadCodeElimination) { - System.out.printf("dead code elimination: deleted %d nodes\n", deletedNodeCount); - } - } - - private static boolean isCFG(Node n) { - return n != null && ((n instanceof Instruction) || n == n.graph().start()); - } - - private void iterateSuccessors() { - for (Node current : worklist) { - for (Node successor : current.successors()) { - worklist.add(successor); - } - } - } - - private void disconnectCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { - // iterate backwards so that the predecessor indexes in removePhiPredecessor are correct - for (int i = node.successors().size() - 1; i >= 0; i--) { - Node successor = node.successors().get(i); - if (successor != Node.Null && worklist.isMarked(successor)) { - if (successor instanceof Merge) { - ((Merge) successor).removePhiPredecessor(node); - } - } - } - node.successors().clearAll(); - node.inputs().clearAll(); - } - } - } - - private void deleteCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { - node.delete(); - deletedNodeCount++; - } - } - } - - private void iterateInputs() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && worklist.isMarked(node)) { - for (Node input : node.inputs()) { - worklist.add(input); - } - } - } - for (Node current : worklist) { - for (Node input : current.inputs()) { - worklist.add(input); - } - } - } - - private void disconnectNonCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { - node.inputs().clearAll(); - } - } - } - - private void deleteNonCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { - node.delete(); - deletedNodeCount++; - } - } - } -} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/GraphBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/GraphBuilder.java Wed Jun 08 13:04:17 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1552 +0,0 @@ -/* - * Copyright (c) 2009, 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.graph; - -import static com.sun.cri.bytecode.Bytecodes.*; -import static java.lang.reflect.Modifier.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.debug.*; -import com.oracle.max.graal.compiler.graph.BlockMap.*; -import com.oracle.max.graal.compiler.graph.BlockMap.Block; -import com.oracle.max.graal.compiler.ir.*; -import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.compiler.util.*; -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.*; -import com.sun.cri.ri.RiType.*; - -/** - * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. - * A number of optimizations may be performed during parsing of the bytecode, including value - * numbering, inlining, constant folding, strength reduction, etc. - */ -public final class GraphBuilder extends Phase { - - /** - * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace - * the bytecode instructions as they are parsed. - */ - public static final int TRACELEVEL_INSTRUCTIONS = 1; - - /** - * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace - * the frame state before each bytecode instruction as it is parsed. - */ - public static final int TRACELEVEL_STATE = 2; - - private final C1XCompilation compilation; - private 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 FrameStateBuilder frameState; // the current execution state - - // bci-to-block mapping - private Block[] blockFromBci; - private ArrayList blockList; - - private int nextBlockNumber; - - private Value methodSynchronizedObject; - private CiExceptionHandler syncHandler; - - private Block unwindBlock; - private Block returnBlock; - - // 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) { - return o1.blockID - o2.blockID; - } - }); - - private Instruction lastInstr; // the last instruction added - - private final Set blocksOnWorklist = new HashSet(); - private final Set blocksVisited = new HashSet(); - - private final boolean createUnwind; - - - /** - * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. - * - * @param compilation the compilation - * @param ir the IR to build the graph into - * @param graph - */ - public GraphBuilder(C1XCompilation compilation, RiMethod method, boolean createUnwind) { - this.compilation = compilation; - - this.runtime = compilation.runtime; - this.method = method; - this.stats = compilation.stats; - this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; - this.stream = new BytecodeStream(method.code()); - - this.constantPool = runtime.getConstantPool(method); - this.createUnwind = createUnwind; - } - - @Override - protected void run(Graph graph) { - assert graph != null; - this.graph = (CompilerGraph) graph; - this.frameState = new FrameStateBuilder(method, graph); - build(); - } - - /** - * Builds the graph for a the specified {@code IRScope}. - * - * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception - * handler and the method is not synchronized - */ - private void build() { - if (log != null) { - log.println(); - log.println("Compiling " + method); - } - - // 2. compute the block map, setup exception handlers and get the entrypoint(s) - BlockMap blockMap = compilation.getBlockMap(method); - - blockList = new ArrayList(blockMap.blocks); - blockFromBci = new Block[method.code().length]; - for (int i = 0; i < blockList.size(); i++) { - int blockID = nextBlockNumber(); - assert blockID == i; - Block block = blockList.get(i); - if (block.startBci >= 0) { - blockFromBci[block.startBci] = block; - } - } - - // 1. create the start block - Block startBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI); - markOnWorkList(startBlock); - lastInstr = createTarget(startBlock, frameState); - graph.start().setStart(lastInstr); - - if (isSynchronized(method.accessFlags())) { - // 4A.1 add a monitor enter to the start block - 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, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); - } else { - // 4B.1 simply finish the start block - finishStartBlock(startBlock); - - if (createUnwind) { - syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); - } - } - - // 5. SKIPPED: look for intrinsics - - // 6B.1 do the normal parsing - addToWorkList(blockFromBci[0]); - iterateAllBlocks(); - - // remove Placeholders - for (Node n : graph.getNodes()) { - if (n instanceof Placeholder) { - Placeholder p = (Placeholder) n; - assert p.blockPredecessors().size() == 1; - Node pred = p.blockPredecessors().get(0); - int predIndex = p.predecessorsIndex().get(0); - pred.successors().setAndClear(predIndex, p, 0); - p.delete(); - } - } - - // 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 (delete) { - n.delete(); - } - } - } - } - - private int nextBlockNumber() { - stats.blockCount++; - return nextBlockNumber++; - } - - private Block nextBlock(int bci) { - Block block = new Block(); - block.startBci = bci; - block.endBci = bci; - block.blockID = nextBlockNumber(); - return block; - } - - private Block unwindBlock() { - if (unwindBlock == null) { - unwindBlock = new Block(); - unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - unwindBlock.blockID = nextBlockNumber(); - addToWorkList(unwindBlock); - } - return unwindBlock; - } - - private Block returnBlock() { - if (returnBlock == null) { - returnBlock = new Block(); - returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - returnBlock.blockID = nextBlockNumber(); - addToWorkList(returnBlock); - } - return returnBlock; - } - - private void markOnWorkList(Block block) { - blocksOnWorklist.add(block); - } - - private boolean isOnWorkList(Block block) { - return blocksOnWorklist.contains(block); - } - - private void markVisited(Block block) { - blocksVisited.add(block); - } - - private boolean isVisited(Block block) { - return blocksVisited.contains(block); - } - - private void finishStartBlock(Block startBlock) { - assert bci() == 0; - Instruction target = createTargetAt(0, frameState); - appendGoto(target); - } - - public void mergeOrClone(Block target, FrameStateAccess newState) { - Instruction first = target.firstInstruction; - if (target.isLoopHeader && isVisited(target)) { - first = ((LoopBegin) first).loopEnd(); - } - assert first instanceof StateSplit; - - int bci = target.startBci; - - FrameState existingState = ((StateSplit) first).stateBefore(); - - if (existingState == null) { - // copy state because it is modified - FrameState duplicate = newState.duplicate(bci); - - // if the block is a loop header, insert all necessary phis - if (first instanceof LoopBegin && target.isLoopHeader) { - assert first instanceof Merge; - insertLoopPhis((Merge) first, duplicate); - ((Merge) first).setStateBefore(duplicate); - } else { - ((StateSplit) first).setStateBefore(duplicate); - } - } else { - if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { - // stacks or locks do not match--bytecodes would not verify - TTY.println(existingState.toString()); - TTY.println(newState.duplicate(0).toString()); - throw new CiBailout("stack or locks do not match"); - } - assert existingState.localsSize() == newState.localsSize(); - assert existingState.stackSize() == newState.stackSize(); - - if (first instanceof Placeholder) { - assert !target.isLoopHeader; - Merge merge = new Merge(graph); - - Placeholder p = (Placeholder) first; - assert p.next() == null; - p.replace(merge); - target.firstInstruction = merge; - merge.setStateBefore(existingState); - first = merge; - } - - existingState.merge((Merge) first, newState); - } - - for (int j = 0; j < frameState.localsSize() + frameState.stackSize(); ++j) { - if (frameState.valueAt(j) != null) { - assert !frameState.valueAt(j).isDeleted(); - } - } - } - - private void insertLoopPhis(Merge merge, FrameState newState) { - int stackSize = newState.stackSize(); - for (int i = 0; i < stackSize; i++) { - // always insert phis for the stack - Value x = newState.stackAt(i); - if (x != null) { - newState.setupPhiForStack(merge, i).addInput(x); - } - } - int localsSize = newState.localsSize(); - for (int i = 0; i < localsSize; i++) { - Value x = newState.localAt(i); - if (x != null) { - newState.setupPhiForLocal(merge, i).addInput(x); - } - } - } - - public BytecodeStream stream() { - return stream; - } - - public int bci() { - return stream.currentBCI(); - } - - private void loadLocal(int index, CiKind kind) { - frameState.push(kind, frameState.loadLocal(index)); - } - - private void storeLocal(CiKind kind, int index) { - frameState.storeLocal(index, frameState.pop(kind)); - } - - public boolean covers(RiExceptionHandler handler, int bci) { - return handler.startBCI() <= bci && bci < handler.endBCI(); - } - - public boolean isCatchAll(RiExceptionHandler handler) { - return handler.catchTypeCPI() == 0; - } - - private Instruction handleException(Value exceptionObject, int bci) { - assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; - - RiExceptionHandler firstHandler = null; - RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); - // join with all potential exception handlers - if (exceptionHandlers != null) { - for (RiExceptionHandler handler : exceptionHandlers) { - // if the handler covers this bytecode index, add it to the list - if (covers(handler, bci)) { - firstHandler = handler; - break; - } - } - } - - if (firstHandler == null) { - firstHandler = syncHandler; - } - - if (firstHandler != null) { - compilation.setHasExceptionHandlers(); - - Block dispatchBlock = null; - for (Block block : blockList) { - if (block instanceof ExceptionBlock) { - ExceptionBlock excBlock = (ExceptionBlock) block; - if (excBlock.handler == firstHandler) { - dispatchBlock = block; - break; - } - } - } - // if there's no dispatch block then the catch block needs to be a catch all - if (dispatchBlock == null) { - assert isCatchAll(firstHandler); - int handlerBCI = firstHandler.handlerBCI(); - if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) { - dispatchBlock = unwindBlock(); - } else { - dispatchBlock = blockFromBci[handlerBCI]; - } - } - FrameState entryState = frameState.duplicateWithEmptyStack(bci); - - StateSplit entry = new Placeholder(graph); - entry.setStateBefore(entryState); - - Instruction currentNext = entry; - Value currentExceptionObject = exceptionObject; - if (currentExceptionObject == null) { - ExceptionObject exception = new ExceptionObject(graph); - entry.setNext(exception); - currentNext = exception; - currentExceptionObject = exception; - } - FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, currentExceptionObject); - - Instruction successor = createTarget(dispatchBlock, stateWithException); - currentNext.setNext(successor); - return entry; - } - return null; - } - - private void genLoadConstant(int cpi) { - Object con = constantPool.lookupConstant(cpi); - - if (con instanceof RiType) { - // this is a load of class constant which might be unresolved - RiType riType = (RiType) con; - if (!riType.isResolved()) { - append(new Deoptimize(graph)); - frameState.push(CiKind.Object, append(Constant.forObject(null, graph))); - } else { - frameState.push(CiKind.Object, append(new Constant(riType.getEncoding(Representation.JavaClass), graph))); - } - } else if (con instanceof CiConstant) { - CiConstant constant = (CiConstant) con; - frameState.push(constant.kind.stackKind(), appendConstant(constant)); - } else { - throw new Error("lookupConstant returned an object of incorrect type"); - } - } - - private void genLoadIndexed(CiKind kind) { - Value index = frameState.ipop(); - Value array = frameState.apop(); - Value length = append(new ArrayLength(array, graph)); - Value v = append(new LoadIndexed(array, index, length, kind, graph)); - frameState.push(kind.stackKind(), v); - } - - private void genStoreIndexed(CiKind kind) { - Value value = frameState.pop(kind.stackKind()); - Value index = frameState.ipop(); - Value array = frameState.apop(); - Value length = append(new ArrayLength(array, graph)); - StoreIndexed result = new StoreIndexed(array, index, length, kind, value, graph); - append(result); - } - - private void stackOp(int opcode) { - switch (opcode) { - case POP: { - frameState.xpop(); - break; - } - case POP2: { - frameState.xpop(); - frameState.xpop(); - break; - } - case DUP: { - Value w = frameState.xpop(); - frameState.xpush(w); - frameState.xpush(w); - break; - } - case DUP_X1: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP_X2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X1: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - Value w4 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w4); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case SWAP: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - break; - } - default: - throw Util.shouldNotReachHere(); - } - - } - - private void genArithmeticOp(CiKind kind, int opcode) { - genArithmeticOp(kind, opcode, false); - } - - private void genArithmeticOp(CiKind result, int opcode, boolean canTrap) { - Value y = frameState.pop(result); - Value x = frameState.pop(result); - boolean isStrictFP = isStrict(method.accessFlags()); - Arithmetic v; - switch(opcode){ - case IADD: - case LADD: v = new IntegerAdd(result, x, y, graph); break; - case FADD: - case DADD: v = new FloatAdd(result, x, y, isStrictFP, graph); break; - case ISUB: - case LSUB: v = new IntegerSub(result, x, y, graph); break; - case FSUB: - case DSUB: v = new FloatSub(result, x, y, isStrictFP, graph); break; - case IMUL: - case LMUL: v = new IntegerMul(result, x, y, graph); break; - case FMUL: - case DMUL: v = new FloatMul(result, x, y, isStrictFP, graph); break; - case IDIV: - case LDIV: v = new IntegerDiv(result, x, y, graph); break; - case FDIV: - case DDIV: v = new FloatDiv(result, x, y, isStrictFP, graph); break; - case IREM: - case LREM: v = new IntegerRem(result, x, y, graph); break; - case FREM: - case DREM: v = new FloatRem(result, x, y, isStrictFP, graph); break; - default: - throw new CiBailout("should not reach"); - } - Value result1 = append(v); - if (canTrap) { - append(new ValueAnchor(result1, graph)); - } - frameState.push(result, result1); - } - - private void genNegateOp(CiKind kind) { - frameState.push(kind, append(new Negate(frameState.pop(kind), graph))); - } - - private void genShiftOp(CiKind kind, int opcode) { - Value s = frameState.ipop(); - Value x = frameState.pop(kind); - Shift v; - switch(opcode){ - case ISHL: - case LSHL: v = new LeftShift(kind, x, s, graph); break; - case ISHR: - case LSHR: v = new RightShift(kind, x, s, graph); break; - case IUSHR: - case LUSHR: v = new UnsignedRightShift(kind, x, s, graph); break; - default: - throw new CiBailout("should not reach"); - } - frameState.push(kind, append(v)); - } - - private void genLogicOp(CiKind kind, int opcode) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - Logic v; - switch(opcode){ - case IAND: - case LAND: v = new And(kind, x, y, graph); break; - case IOR: - case LOR: v = new Or(kind, x, y, graph); break; - case IXOR: - case LXOR: v = new Xor(kind, x, y, graph); break; - default: - throw new CiBailout("should not reach"); - } - frameState.push(kind, append(v)); - } - - private void genCompareOp(CiKind kind, int opcode, CiKind resultKind) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - Value value = append(new NormalizeCompare(opcode, resultKind, x, y, graph)); - if (!resultKind.isVoid()) { - frameState.ipush(value); - } - } - - private void genConvert(int opcode, CiKind from, CiKind to) { - CiKind tt = to.stackKind(); - frameState.push(tt, append(new Convert(opcode, frameState.pop(from.stackKind()), tt, graph))); - } - - private void genIncrement() { - int index = stream().readLocalIndex(); - int delta = stream().readIncrement(); - Value x = frameState.localAt(index); - Value y = append(Constant.forInt(delta, graph)); - frameState.storeLocal(index, append(new IntegerAdd(CiKind.Int, x, y, graph))); - } - - private void genGoto(int fromBCI, int toBCI) { - appendGoto(createTargetAt(toBCI, frameState)); - } - - private void ifNode(Value x, Condition cond, Value y) { - assert !x.isDeleted() && !y.isDeleted(); - If ifNode = new If(new Compare(x, cond, y, graph), graph); - append(ifNode); - Instruction tsucc = createTargetAt(stream().readBranchDest(), frameState); - ifNode.setBlockSuccessor(0, tsucc); - Instruction fsucc = createTargetAt(stream().nextBCI(), frameState); - ifNode.setBlockSuccessor(1, fsucc); - } - - private void genIfZero(Condition cond) { - Value y = appendConstant(CiConstant.INT_0); - Value x = frameState.ipop(); - ifNode(x, cond, y); - } - - private void genIfNull(Condition cond) { - Value y = appendConstant(CiConstant.NULL_OBJECT); - Value x = frameState.apop(); - ifNode(x, cond, y); - } - - private void genIfSame(CiKind kind, Condition cond) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - assert !x.isDeleted() && !y.isDeleted(); - ifNode(x, cond, y); - } - - private void genThrow(int bci) { - Value exception = frameState.apop(); - append(new NullCheck(exception, graph)); - - Instruction entry = handleException(exception, bci); - if (entry != null) { - append(entry); - } else { - frameState.clearStack(); - frameState.apush(exception); - appendGoto(createTarget(unwindBlock(), frameState)); - } - } - - private void genCheckCast() { - int cpi = stream().readCPI(); - RiType type = constantPool.lookupType(cpi, CHECKCAST); - boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); - Value object = frameState.apop(); - if (typeInstruction != null) { - frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); - } else { - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genInstanceOf() { - int cpi = stream().readCPI(); - RiType type = constantPool.lookupType(cpi, INSTANCEOF); - boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); - Value object = frameState.apop(); - if (typeInstruction != null) { - frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); - } else { - frameState.ipush(appendConstant(CiConstant.INT_0)); - } - } - - void genNewInstance(int cpi) { - RiType type = constantPool.lookupType(cpi, NEW); - if (type.isResolved()) { - NewInstance n = new NewInstance(type, cpi, constantPool, graph); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genNewTypeArray(int typeCode) { - CiKind kind = CiKind.fromArrayTypeCode(typeCode); - 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); - Value length = frameState.ipop(); - if (type.isResolved()) { - NewArray n = new NewObjectArray(type, length, graph); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - - } - - private void genNewMultiArray(int cpi) { - 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); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genGetField(int cpi, RiField field) { - CiKind kind = field.kind(); - Value receiver = frameState.apop(); - if (field.isResolved()) { - LoadField load = new LoadField(receiver, field, graph); - appendOptimizedLoadField(kind, load); - } else { - append(new Deoptimize(graph)); - frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); - } - } - - private void genPutField(int cpi, RiField field) { - Value value = frameState.pop(field.kind().stackKind()); - Value receiver = frameState.apop(); - if (field.isResolved()) { - StoreField store = new StoreField(receiver, field, value, graph); - appendOptimizedStoreField(store); - } else { - append(new Deoptimize(graph)); - } - } - - private void genGetStatic(int cpi, RiField field) { - RiType holder = field.holder(); - boolean isInitialized = field.isResolved(); - CiConstant constantValue = null; - if (isInitialized) { - constantValue = field.constantValue(null); - } - if (constantValue != null) { - frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue)); - } else { - Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); - CiKind kind = field.kind(); - if (container != null) { - LoadField load = new LoadField(container, field, graph); - appendOptimizedLoadField(kind, load); - } else { - append(new Deoptimize(graph)); - frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); - } - } - } - - private void genPutStatic(int cpi, RiField field) { - RiType holder = field.holder(); - Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi); - Value value = frameState.pop(field.kind().stackKind()); - if (container != null) { - StoreField store = new StoreField(container, field, value, graph); - appendOptimizedStoreField(store); - } else { - append(new Deoptimize(graph)); - } - } - - private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { - if (initialized) { - return appendConstant(holder.getEncoding(representation)); - } else { - append(new Deoptimize(graph)); - return null; - } - } - - private void appendOptimizedStoreField(StoreField store) { - append(store); - } - - private void appendOptimizedLoadField(CiKind kind, LoadField load) { - // append the load to the instruction - Value optimized = append(load); - frameState.push(kind.stackKind(), optimized); - } - - private void genInvokeStatic(RiMethod target, int cpi, RiConstantPool constantPool) { - RiType holder = target.holder(); - boolean isInitialized = target.isResolved() && holder.isInitialized(); - if (!isInitialized && C1XOptions.ResolveClassBeforeStaticInvoke) { - // Re-use the same resolution code as for accessing a static field. Even though - // the result of resolution is not used by the invocation (only the side effect - // of initialization is required), it can be commoned with static field accesses. - genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); - } - Value[] args = frameState.popArguments(target.signature().argumentSlots(false)); - appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); - } - - private void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool); - - } - - private void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool); - - } - - private void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - invokeDirect(target, args, knownHolder, cpi, constantPool); - - } - - private void genInvokeIndirect(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { - Value receiver = args[0]; - // attempt to devirtualize the call - if (target.isResolved()) { - RiType klass = target.holder(); - - // 0. check for trivial cases - if (target.canBeStaticallyBound() && !isAbstract(target.accessFlags())) { - // check for trivial cases (e.g. final methods, nonvirtual methods) - invokeDirect(target, args, target.holder(), cpi, constantPool); - return; - } - // 1. check if the exact type of the receiver can be determined - RiType exact = getExactType(klass, receiver); - if (exact != null && exact.isResolved()) { - // either the holder class is exact, or the receiver object has an exact type - invokeDirect(exact.resolveMethodImpl(target), args, exact, cpi, constantPool); - return; - } - } - // devirtualization failed, produce an actual invokevirtual - appendInvoke(opcode, target, args, cpi, constantPool); - } - - private CiKind returnKind(RiMethod target) { - return target.signature().returnKind(); - } - - private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { - appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); - } - - 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(method.holder()), graph); - Value result = appendWithBCI(invoke); - invoke.setExceptionEdge(handleException(null, bci())); - frameState.pushReturn(resultType, result); - } - - private RiType getExactType(RiType staticType, Value receiver) { - RiType exact = staticType.exactType(); - if (exact == null) { - exact = receiver.exactType(); - if (exact == null) { - if (receiver.isConstant()) { - exact = runtime.getTypeOf(receiver.asConstant()); - } - if (exact == null) { - RiType declared = receiver.declaredType(); - exact = declared == null || !declared.isResolved() ? null : declared.exactType(); - } - } - } - return exact; - } - - private void callRegisterFinalizer() { - Value receiver = frameState.loadLocal(0); - RiType declaredType = receiver.declaredType(); - RiType receiverType = declaredType; - RiType exactType = receiver.exactType(); - if (exactType == null && declaredType != null) { - exactType = declaredType.exactType(); - } - 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 = method.holder(); - exactType = receiverType.exactType(); - } - boolean needsCheck = true; - if (exactType != null) { - // we have an exact type - needsCheck = exactType.hasFinalizer(); - } else { - // if either the declared type of receiver or the holder can be assumed to have no finalizers - if (declaredType != null && !declaredType.hasFinalizableSubclass()) { - if (compilation.recordNoFinalizableSubclassAssumption(declaredType)) { - needsCheck = false; - } - } - - if (receiverType != null && !receiverType.hasFinalizableSubclass()) { - if (compilation.recordNoFinalizableSubclassAssumption(receiverType)) { - needsCheck = false; - } - } - } - - if (needsCheck) { - // append a call to the finalizer registration - append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph)); - C1XMetrics.InlinedFinalizerChecks++; - } - } - - private void genReturn(Value x) { - frameState.clearStack(); - if (x != null) { - frameState.push(x.kind, x); - } - appendGoto(createTarget(returnBlock(), frameState)); - } - - private void genMonitorEnter(Value x, int bci) { - int lockNumber = frameState.locksSize(); - MonitorAddress lockAddress = null; - if (runtime.sizeOfBasicObjectLock() != 0) { - lockAddress = new MonitorAddress(lockNumber, graph); - append(lockAddress); - } - MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); - appendWithBCI(monitorEnter); - frameState.lock(x); - if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { - monitorEnter.setStateAfter(frameState.create(0)); - } - } - - private void genMonitorExit(Value x) { - int lockNumber = frameState.locksSize() - 1; - if (lockNumber < 0) { - throw new CiBailout("monitor stack underflow"); - } - MonitorAddress lockAddress = null; - if (runtime.sizeOfBasicObjectLock() != 0) { - lockAddress = new MonitorAddress(lockNumber, graph); - append(lockAddress); - } - appendWithBCI(new MonitorExit(x, lockAddress, lockNumber, graph)); - frameState.unlock(); - } - - private void genJsr(int dest) { - throw new CiBailout("jsr/ret not supported"); - } - - private void genRet(int localIndex) { - throw new CiBailout("jsr/ret not supported"); - } - - private void genTableswitch() { - int bci = bci(); - Value value = frameState.ipop(); - BytecodeTableSwitch ts = new BytecodeTableSwitch(stream(), bci); - int max = ts.numberOfCases(); - List list = new ArrayList(max + 1); - List offsetList = new ArrayList(max + 1); - for (int i = 0; i < max; i++) { - // add all successors to the successor list - int offset = ts.offsetAt(i); - list.add(null); - offsetList.add(offset); - } - int offset = ts.defaultOffset(); - list.add(null); - offsetList.add(offset); - TableSwitch tableSwitch = new TableSwitch(value, list, ts.lowKey(), graph); - for (int i = 0; i < offsetList.size(); ++i) { - tableSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); - } - append(tableSwitch); - } - - private void genLookupswitch() { - int bci = bci(); - Value value = frameState.ipop(); - BytecodeLookupSwitch ls = new BytecodeLookupSwitch(stream(), bci); - int max = ls.numberOfCases(); - List list = new ArrayList(max + 1); - List offsetList = new ArrayList(max + 1); - int[] keys = new int[max]; - for (int i = 0; i < max; i++) { - // add all successors to the successor list - int offset = ls.offsetAt(i); - list.add(null); - offsetList.add(offset); - keys[i] = ls.keyAt(i); - } - int offset = ls.defaultOffset(); - list.add(null); - offsetList.add(offset); - LookupSwitch lookupSwitch = new LookupSwitch(value, list, keys, graph); - for (int i = 0; i < offsetList.size(); ++i) { - lookupSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); - } - append(lookupSwitch); - } - - private Value appendConstant(CiConstant constant) { - return append(new Constant(constant, graph)); - } - - private Value append(Instruction x) { - return appendWithBCI(x); - } - - private Value append(Value v) { - return v; - } - - private Value appendWithBCI(Instruction x) { - assert x.predecessors().size() == 0 : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - lastInstr.setNext(x); - - lastInstr = x; - if (++stats.nodeCount >= C1XOptions.MaximumInstructionCount) { - // bailout if we've exceeded the maximum inlining size - throw new CiBailout("Method and/or inlining is too large"); - } - - return x; - } - - private Instruction createTargetAt(int bci, FrameStateAccess stateAfter) { - return createTarget(blockFromBci[bci], stateAfter); - } - - private Instruction createTarget(Block block, FrameStateAccess stateAfter) { - assert block != null && stateAfter != null; - assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : "non-loop block must be iterated after all its predecessors"; - - if (block.isExceptionEntry) { - assert stateAfter.stackSize() == 1; - } - - if (block.firstInstruction == null) { - if (block.isLoopHeader) { -// block.firstInstruction = new Merge(block.startBci, graph); - - LoopBegin loopBegin = new LoopBegin(graph); - LoopEnd loopEnd = new LoopEnd(graph); - loopEnd.setLoopBegin(loopBegin); - block.firstInstruction = loopBegin; - } else { - block.firstInstruction = new Placeholder(graph); - } - } - mergeOrClone(block, stateAfter); - addToWorkList(block); - - if (block.firstInstruction instanceof LoopBegin && isVisited(block)) { - return ((LoopBegin) block.firstInstruction).loopEnd(); - } else { - return block.firstInstruction; - } - } - - private Value synchronizedObject(FrameStateAccess state, RiMethod target) { - if (isStatic(target.accessFlags())) { - Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph); - return append(classConstant); - } else { - return state.localAt(0); - } - } - - private void iterateAllBlocks() { - Block block; - while ((block = removeFromWorkList()) != null) { - - // remove blocks that have no predecessors by the time it their bytecodes are parsed - if (block.firstInstruction == null) { - markVisited(block); - continue; - } - - if (!isVisited(block)) { - markVisited(block); - // now parse the block - frameState.initializeFrom(((StateSplit) block.firstInstruction).stateBefore()); - lastInstr = block.firstInstruction; - assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID; - - if (block == returnBlock) { - createReturnBlock(block); - } else if (block == unwindBlock) { - createUnwindBlock(block); - } else if (block instanceof ExceptionBlock) { - createExceptionDispatch((ExceptionBlock) block); - } else { - iterateBytecodesForBlock(block); - } - } - } - for (Block b : blocksVisited) { - if (b.isLoopHeader) { - LoopBegin begin = (LoopBegin) b.firstInstruction; - LoopEnd end = begin.loopEnd(); - -// This can happen with degenerated loops like this one: -// for (;;) { -// try { -// break; -// } catch (UnresolvedException iioe) { -// } -// } - if (end.stateBefore() != null) { - begin.stateBefore().merge(begin, end.stateBefore()); - } else { - end.delete(); - Merge merge = new Merge(graph); - merge.successors().setAndClear(merge.nextIndex(), begin, begin.nextIndex()); - begin.replace(merge); - } - } - } - } - - private void createUnwindBlock(Block block) { - if (Modifier.isSynchronized(method.accessFlags())) { - genMonitorExit(methodSynchronizedObject); - } - append(graph.createUnwind(frameState.apop())); - } - - private void createReturnBlock(Block block) { - if (method.isConstructor() && method.holder().superType() == null) { - callRegisterFinalizer(); - } - 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(methodSynchronizedObject); - } - append(graph.createReturn(x)); - } - - private void createExceptionDispatch(ExceptionBlock block) { - if (block.handler == null) { - assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize(); - createUnwindBlock(block); - } else { - assert frameState.stackSize() == 1; - - Block nextBlock = block.next == null ? unwindBlock() : block.next; - if (block.handler.catchType().isResolved()) { - Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState); - Instruction nextDispatch = createTarget(nextBlock, frameState); - append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph)); - } else { - Deoptimize deopt = new Deoptimize(graph); - deopt.setMessage("unresolved " + block.handler.catchType().name()); - append(deopt); - Instruction nextDispatch = createTarget(nextBlock, frameState); - appendGoto(nextDispatch); - } - } - } - - private void appendGoto(Instruction target) { - lastInstr.setNext(target); - } - - private void iterateBytecodesForBlock(Block block) { - assert frameState != null; - - stream.setBCI(block.startBci); - - int endBCI = stream.endBCI(); - boolean blockStart = true; - - int bci = block.startBci; - while (bci < endBCI) { - Block nextBlock = blockFromBci[bci]; - if (nextBlock != null && nextBlock != block) { - assert !nextBlock.isExceptionEntry; - // we fell through to the next block, add a goto and break - appendGoto(createTarget(nextBlock, frameState)); - break; - } - // read the opcode - int opcode = stream.currentBC(); - - traceState(); - traceInstruction(bci, opcode, blockStart); - processBytecode(bci, opcode); - - if (Schedule.isBlockEnd(lastInstr) || lastInstr.next() != null) { - break; - } - - stream.next(); - bci = stream.currentBCI(); - if (lastInstr instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) lastInstr; - if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { - stateSplit.setStateAfter(frameState.create(bci)); - } - } - blockStart = false; - } - } - - 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)); - 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)); - } - for (int i = 0; i < frameState.stackSize(); ++i) { - Value value = frameState.stackAt(i); - log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); - } - for (int i = 0; i < frameState.locksSize(); ++i) { - Value value = frameState.lockAt(i); - log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); - } - } - } - - private void processBytecode(int bci, int opcode) { - int cpi; - - // Checkstyle: stop - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); break; - case ICONST_M1 : frameState.ipush(appendConstant(CiConstant.INT_MINUS_1)); break; - case ICONST_0 : frameState.ipush(appendConstant(CiConstant.INT_0)); break; - case ICONST_1 : frameState.ipush(appendConstant(CiConstant.INT_1)); break; - case ICONST_2 : frameState.ipush(appendConstant(CiConstant.INT_2)); break; - case ICONST_3 : frameState.ipush(appendConstant(CiConstant.INT_3)); break; - case ICONST_4 : frameState.ipush(appendConstant(CiConstant.INT_4)); break; - case ICONST_5 : frameState.ipush(appendConstant(CiConstant.INT_5)); break; - case LCONST_0 : frameState.lpush(appendConstant(CiConstant.LONG_0)); break; - case LCONST_1 : frameState.lpush(appendConstant(CiConstant.LONG_1)); break; - case FCONST_0 : frameState.fpush(appendConstant(CiConstant.FLOAT_0)); break; - case FCONST_1 : frameState.fpush(appendConstant(CiConstant.FLOAT_1)); break; - case FCONST_2 : frameState.fpush(appendConstant(CiConstant.FLOAT_2)); break; - case DCONST_0 : frameState.dpush(appendConstant(CiConstant.DOUBLE_0)); break; - case DCONST_1 : frameState.dpush(appendConstant(CiConstant.DOUBLE_1)); break; - case BIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI()); break; - case ILOAD : loadLocal(stream.readLocalIndex(), CiKind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), CiKind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), CiKind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), CiKind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), CiKind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, CiKind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, CiKind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, CiKind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, CiKind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, CiKind.Object); break; - case IALOAD : genLoadIndexed(CiKind.Int ); break; - case LALOAD : genLoadIndexed(CiKind.Long ); break; - case FALOAD : genLoadIndexed(CiKind.Float ); break; - case DALOAD : genLoadIndexed(CiKind.Double); break; - case AALOAD : genLoadIndexed(CiKind.Object); break; - case BALOAD : genLoadIndexed(CiKind.Byte ); break; - case CALOAD : genLoadIndexed(CiKind.Char ); break; - case SALOAD : genLoadIndexed(CiKind.Short ); break; - case ISTORE : storeLocal(CiKind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(CiKind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(CiKind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(CiKind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(CiKind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(CiKind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(CiKind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(CiKind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(CiKind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(CiKind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(CiKind.Int ); break; - case LASTORE : genStoreIndexed(CiKind.Long ); break; - case FASTORE : genStoreIndexed(CiKind.Float ); break; - case DASTORE : genStoreIndexed(CiKind.Double); break; - case AASTORE : genStoreIndexed(CiKind.Object); break; - case BASTORE : genStoreIndexed(CiKind.Byte ); break; - case CASTORE : genStoreIndexed(CiKind.Char ); break; - case SASTORE : genStoreIndexed(CiKind.Short ); break; - case POP : // fall through - case POP2 : // fall through - case DUP : // fall through - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(CiKind.Int, opcode); break; - case IDIV : // fall through - case IREM : genArithmeticOp(CiKind.Int, opcode, true); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(CiKind.Long, opcode); break; - case LDIV : // fall through - case LREM : genArithmeticOp(CiKind.Long, opcode, true); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(CiKind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(CiKind.Double, opcode); break; - case INEG : genNegateOp(CiKind.Int); break; - case LNEG : genNegateOp(CiKind.Long); break; - case FNEG : genNegateOp(CiKind.Float); break; - case DNEG : genNegateOp(CiKind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(CiKind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(CiKind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(CiKind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(CiKind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2L : genConvert(opcode, CiKind.Int , CiKind.Long ); break; - case I2F : genConvert(opcode, CiKind.Int , CiKind.Float ); break; - case I2D : genConvert(opcode, CiKind.Int , CiKind.Double); break; - case L2I : genConvert(opcode, CiKind.Long , CiKind.Int ); break; - case L2F : genConvert(opcode, CiKind.Long , CiKind.Float ); break; - case L2D : genConvert(opcode, CiKind.Long , CiKind.Double); break; - case F2I : genConvert(opcode, CiKind.Float , CiKind.Int ); break; - case F2L : genConvert(opcode, CiKind.Float , CiKind.Long ); break; - case F2D : genConvert(opcode, CiKind.Float , CiKind.Double); break; - case D2I : genConvert(opcode, CiKind.Double, CiKind.Int ); break; - case D2L : genConvert(opcode, CiKind.Double, CiKind.Long ); break; - case D2F : genConvert(opcode, CiKind.Double, CiKind.Float ); break; - case I2B : genConvert(opcode, CiKind.Int , CiKind.Byte ); break; - case I2C : genConvert(opcode, CiKind.Int , CiKind.Char ); break; - case I2S : genConvert(opcode, CiKind.Int , CiKind.Short ); break; - case LCMP : genCompareOp(CiKind.Long, opcode, CiKind.Int); break; - case FCMPL : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; - case FCMPG : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; - case DCMPL : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; - case DCMPG : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(CiKind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(CiKind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(CiKind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(CiKind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(CiKind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(CiKind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(frameState.peekKind(), Condition.EQ); break; - case IF_ACMPNE : genIfSame(frameState.peekKind(), Condition.NE); break; - case GOTO : genGoto(stream.currentBCI(), stream.readBranchDest()); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genTableswitch(); break; - case LOOKUPSWITCH : genLookupswitch(); break; - case IRETURN : genReturn(frameState.ipop()); break; - case LRETURN : genReturn(frameState.lpop()); break; - case FRETURN : genReturn(frameState.fpop()); break; - 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 NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(stream.currentBCI()); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.currentBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(stream.currentBCI(), stream.readFarBranchDest()); break; - case JSR_W : genJsr(stream.readFarBranchDest()); break; - case BREAKPOINT: - throw new CiBailout("concurrent setting of breakpoint"); - default: - throw new CiBailout("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); - } - // Checkstyle: resume - } - - private void traceInstruction(int bci, int opcode, boolean blockStart) { - if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_INSTRUCTIONS && !TTY.isSuppressed()) { - StringBuilder sb = new StringBuilder(40); - sb.append(blockStart ? '+' : '|'); - if (bci < 10) { - sb.append(" "); - } else if (bci < 100) { - sb.append(' '); - } - sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); - for (int i = bci + 1; i < stream.nextBCI(); ++i) { - sb.append(' ').append(stream.readUByte(i)); - } - log.println(sb.toString()); - } - } - - private void genArrayLength() { - frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); - } - - /** - * 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 - * DFNs are earlier in the list). - * @param block the block to add to the work list - */ - private void addToWorkList(Block block) { - if (!isOnWorkList(block)) { - markOnWorkList(block); - sortIntoWorkList(block); - } - } - - private void sortIntoWorkList(Block top) { - workList.offer(top); - } - - /** - * Removes the next block from the worklist. The list is sorted topologically, so the - * block with the lowest depth first number in the list will be removed and returned. - * @return the next block from the worklist; {@code null} if there are no blocks - * in the worklist - */ - private Block removeFromWorkList() { - return workList.poll(); - } -} diff -r adfc15cbcabc -r 693e4e92346b 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 Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Wed Jun 08 13:06:45 2011 +0200 @@ -29,7 +29,7 @@ import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.observer.*; -import com.oracle.max.graal.compiler.opt.*; +import com.oracle.max.graal.compiler.phases.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; @@ -84,24 +84,9 @@ if (C1XOptions.OptCanonicalizer) { new CanonicalizerPhase().apply(graph); - verifyAndPrint("After canonicalization"); } - // Split critical edges. - List nodes = graph.getNodes(); - for (int i = 0; i < nodes.size(); ++i) { - Node n = nodes.get(i); - if (Schedule.trueSuccessorCount(n) > 1) { - for (int j = 0; j < n.successors().size(); ++j) { - Node succ = n.successors().get(j); - if (Schedule.truePredecessorCount(succ) > 1) { - Anchor a = new Anchor(graph); - a.successors().setAndClear(1, n, j); - n.successors().set(j, a); - } - } - } - } + new SplitCriticalEdgesPhase().apply(graph); Schedule schedule = new Schedule(graph); List blocks = schedule.getBlocks(); @@ -157,7 +142,7 @@ private void buildGraph() { // Graph builder must set the startBlock and the osrEntryBlock - new GraphBuilder(compilation, compilation.method, false).apply(compilation.graph); + new GraphBuilderPhase(compilation, compilation.method, false).apply(compilation.graph); // CompilerGraph duplicate = new CompilerGraph(); // Map replacements = new HashMap(); @@ -165,16 +150,16 @@ // duplicate.addDuplicate(compilation.graph.getNodes(), replacements); // compilation.graph = duplicate; - verifyAndPrint("After graph building"); + new DuplicationPhase().apply(compilation.graph); - DeadCodeElimination dce = new DeadCodeElimination(); + DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase(); dce.apply(compilation.graph); if (dce.deletedNodeCount > 0) { verifyAndPrint("After dead code elimination"); } if (C1XOptions.Inline) { - new Inlining(compilation, this).apply(compilation.graph); + new InliningPhase(compilation, this).apply(compilation.graph); } if (C1XOptions.PrintCompilation) { @@ -190,36 +175,17 @@ return orderedBlocks; } - private void print(boolean cfgOnly) { - if (!TTY.isSuppressed()) { - TTY.println("IR for " + compilation.method); - final InstructionPrinter ip = new InstructionPrinter(TTY.out()); - final BlockPrinter bp = new BlockPrinter(this, ip, cfgOnly); - //getHIRStartBlock().iteratePreOrder(bp); - } - } - /** * Verifies the IR and prints it out if the relevant options are set. * @param phase the name of the phase for printing */ public void verifyAndPrint(String phase) { - if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { - TTY.println(phase); - print(false); - } - if (compilation.compiler.isObserved()) { compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, compilation.graph, true, false)); } } public void printGraph(String phase, Graph graph) { - if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { - TTY.println(phase); - print(false); - } - if (compilation.compiler.isObserved()) { compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, graph, true, false)); } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/Inlining.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/Inlining.java Wed Jun 08 13:04:17 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,288 +0,0 @@ -/* - * 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.graph; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.ir.*; -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 Inlining extends Phase { - - private final C1XCompilation compilation; - private final IR ir; - - private final Queue invokes = new ArrayDeque(); - private final Queue methods = new ArrayDeque(); - private int inliningSize; - - public Inlining(C1XCompilation compilation, IR ir) { - this.compilation = compilation; - this.ir = ir; - } - - private void addToQueue(Invoke invoke, RiMethod method) { - invokes.add(invoke); - methods.add(method); - inliningSize += method.code().length; - } - - @Override - protected void run(Graph graph) { - if (!C1XOptions.Inline) { - return; - } - - inliningSize = compilation.method.code().length; - int iterations = C1XOptions.MaximumRecursiveInlineLevel; - do { - for (Node node : graph.getNodes()) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - RiMethod target = invoke.target; - if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { - continue; - } - if (target.canBeStaticallyBound()) { - if (checkInliningConditions(invoke.target)) { - addToQueue(invoke, invoke.target); - } - } else { - RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); - if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { - if (checkInliningConditions(concrete)) { - if (C1XOptions.TraceInlining) { - System.out.println("registering concrete method assumption..."); - } - compilation.assumptions.recordConcreteMethod(invoke.target, concrete); - addToQueue(invoke, concrete); - } - } - } - if (inliningSize > C1XOptions.MaximumInstructionCount) { - break; - } - } - } - - assert invokes.size() == methods.size(); - if (invokes.isEmpty()) { - break; - } - - Invoke invoke; - while ((invoke = invokes.poll()) != null) { - RiMethod method = methods.remove(); - inlineMethod(invoke, method); - } - DeadCodeElimination dce = new DeadCodeElimination(); - dce.apply(graph); - if (dce.deletedNodeCount > 0) { - ir.verifyAndPrint("After dead code elimination"); - } - ir.verifyAndPrint("After inlining iteration"); - - if (inliningSize > C1XOptions.MaximumInstructionCount) { - if (C1XOptions.TraceInlining) { - System.out.println("inlining stopped: MaximumInstructionCount reached"); - } - break; - } - } while(--iterations > 0); - } - - private boolean checkInliningConditions(Invoke invoke) { - String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); - if (invoke.predecessors().size() == 0) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because the invoke is dead code"); - } - return false; - } - return true; - } - - private boolean checkInliningConditions(RiMethod method) { - String name = null; - if (C1XOptions.TraceInlining) { - name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; - } - if (method.code().length > C1XOptions.MaximumInlineSize) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because of code size"); - } - return false; - } - if (!method.holder().isInitialized()) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because of non-initialized class"); - } - return false; - } - return true; - } - - private void inlineMethod(Invoke invoke, RiMethod method) { - String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; - FrameState stateAfter = invoke.stateAfter(); - Instruction exceptionEdge = invoke.exceptionEdge(); - - if (C1XOptions.TraceInlining) { - System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); - } - - CompilerGraph graph = new CompilerGraph(); - new GraphBuilder(compilation, method, true).apply(graph); - - 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 = graph.start(); - for (Node node : graph.getNodes()) { - if (node != null) { - if (node instanceof StartNode) { - assert 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 (C1XOptions.TraceInlining) { - ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); - System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); - } - - assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); - Instruction pred; - if (withReceiver) { - pred = new NullCheck(parameters[0], compilation.graph); - } else { - pred = new Merge(compilation.graph); - } - 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(); - } - -// if (invoke.next() instanceof Merge) { -// ((Merge) invoke.next()).removePhiPredecessor(invoke); -// } -// invoke.successors().clearAll(); - invoke.inputs().clearAll(); - invoke.setExceptionEdge(null); -// invoke.delete(); - - - if (exceptionEdge != null) { - if (unwindNode != null) { - assert unwindNode.predecessors().size() == 1; - assert exceptionEdge.successors().size() == 1; - ExceptionObject obj = (ExceptionObject) exceptionEdge; - - List usages = new ArrayList(obj.usages()); - for (Node usage : usages) { - if (replacements.containsKey(unwindNode.exception())) { - usage.inputs().replace(obj, replacements.get(unwindNode.exception())); - } else { - usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); - } - } - Node unwindDuplicate = duplicates.get(unwindNode); - unwindDuplicate.inputs().clearAll(); - - assert unwindDuplicate.predecessors().size() == 1; - Node unwindPred = unwindDuplicate.predecessors().get(0); - int index = unwindDuplicate.predecessorsIndex().get(0); - unwindPred.successors().setAndClear(index, obj, 0); - - obj.inputs().clearAll(); - obj.delete(); - unwindDuplicate.delete(); - - } - } - - // adjust all frame states that were copied - if (frameStates.size() > 0) { - FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); - for (Node frameState : frameStates) { - ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); - } - } - - if (C1XOptions.TraceInlining) { - ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); - } - } -} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/package-info.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/package-info.java Wed Jun 08 13:06:45 2011 +0200 @@ -35,7 +35,7 @@ * * {@code IR.buildGraph} creates an {@link com.oracle.max.graal.compiler.ir.IRScope topScope} object, * that represents a context for inlining, and then invokes the constructor for the - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder} class, passing the {@link com.oracle.max.graal.compiler.C1XCompilation}, and {@code IR} + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase} class, passing the {@link com.oracle.max.graal.compiler.C1XCompilation}, and {@code IR} * instances, which are cached. The following support objects are created in the constructor: * *
    @@ -44,7 +44,7 @@ *
  • {@code canonicalizer}: an instance of {@link com.oracle.max.graal.compiler.opt.Canonicalizer} *
* - * Now the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#build} is invoked with {@code topScope} as argument. + * Now the {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#build} is invoked with {@code topScope} as argument. * *

{@code GraphBuilder.build}

* @@ -60,20 +60,20 @@ * the statistics are updated. * * - *
  • Next the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope} method is called, with the passed-in {@link com.oracle.max.graal.compiler.ir.IRScope} + *
  • Next the {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#pushRootScope} method is called, with the passed-in {@link com.oracle.max.graal.compiler.ir.IRScope} * object, the {@link com.oracle.max.graal.compiler.graph.BlockMap} returned by build and the {@code startBlock}. (Note: Unlike - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushScope}, this method does not propagate the + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#pushScope}, this method does not propagate the * {@link com.oracle.max.graal.compiler.graph.BlockMap#storesInLoops} field to the {@link com.oracle.max.graal.compiler.ir.IRScope} object, which means that * {@link com.oracle.max.graal.compiler.ir.BlockBegin#insertLoopPhis} will always get null for this value. Is this a bug?). - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope} initializes the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#scopeData} field with a + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#pushRootScope} initializes the {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#scopeData} field with a * {@link com.oracle.max.graal.compiler.graph.ScopeData} instance, with null parent. The - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#compilation} instance is called to get an {@link com.sun.cri.ri.RiConstantPool} - * , which is C1X's interface to constant pool information. The {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock} field is + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#compilation} instance is called to get an {@link com.sun.cri.ri.RiConstantPool} + * , which is C1X's interface to constant pool information. The {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curBlock} field is * set to the {@code startBlock}. *

    * * Now a {@link com.oracle.max.graal.compiler.value.FrameState initialState} object is created by - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#stateAtEntry}. If the method is not static, then a {@link com.oracle.max.graal.compiler.ir.Local} + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#stateAtEntry}. If the method is not static, then a {@link com.oracle.max.graal.compiler.ir.Local} * instance is created at index 0. Since the receiver cannot be {@code null}, the * {@link com.oracle.max.graal.compiler.ir.Value.Flag#NonNull} flag is set. Additional {@link com.oracle.max.graal.compiler.ir.Local} instances are created for the * arguments to the method. The index is incremented by the number of slots occupied by the @@ -83,14 +83,14 @@ * copy since {@code stateBefore} will be {@code null}. *

  • *
  • - * This step sets up three instance fields: {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock} and - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#lastInstr} to {@code startBlock} and - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} to {@code initialState}. (N.B. the setting of {@code curBlock} is - * redundant as it is done in {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope}). + * This step sets up three instance fields: {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curBlock} and + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#lastInstr} to {@code startBlock} and + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curState} to {@code initialState}. (N.B. the setting of {@code curBlock} is + * redundant as it is done in {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#pushRootScope}). *
  • *
  • * Step 4 contains special handling for synchronized methods (TBD), otherwise it calls - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#finishStartBlock} which adds a {@link com.oracle.max.graal.compiler.ir.Base} block as the end of + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#finishStartBlock} which adds a {@link com.oracle.max.graal.compiler.ir.Base} block as the end of * the {@code startBlock}. The {@link com.oracle.max.graal.compiler.ir.Base} block has one successor set to the (entry) block with flag * {@link com.oracle.max.graal.compiler.ir.BlockBegin.BlockFlag#StandardEntry}, that was created by {@link com.oracle.max.graal.compiler.graph.BlockMap#build} (and possibly a * successor to an OSREntry block). @@ -103,26 +103,26 @@ * and {@link com.oracle.max.graal.compiler.C1XOptions#OptIntrinsify} is set, an attempt is made to inline it (TBD). Otherwise, or if the * intrinsification fails, normal processing continues by adding the entry block to the * {@link com.oracle.max.graal.compiler.graph.ScopeData} work list (kept topologically sorted) and calling - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateAllBlocks}. + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#iterateAllBlocks}. *
  • *
  • * Finally there is some cleanup code for synchronized blocks and OSR compilations. *
  • * * - *

    {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateAllBlocks}

    + *

    {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#iterateAllBlocks}

    * {@link com.oracle.max.graal.compiler.graph#iterateAllBlocks} repeatedly removes a block from the work list and, if not already visited, marks it so, - * kills the current memory map, sets {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock}, {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} - * and {@link com.oracle.max.graal.compiler.graph.GraphBuilder#lastInstr} and then calls - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock}. + * kills the current memory map, sets {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curBlock}, {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curState} + * and {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#lastInstr} and then calls + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#iterateBytecodesForBlock}. * * This process continues until all the blocks have been visited (processed) after which control returns to {@code * build}. *

    - *

    {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock}

    + *

    {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#iterateBytecodesForBlock}

    * - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock} performs an abstract interpretation of the bytecodes in the block, appending new + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#iterateBytecodesForBlock} performs an abstract interpretation of the bytecodes in the block, appending new * nodes as necessary, until the last added node is an instance of {@link com.oracle.max.graal.compiler.ir.BlockEnd}. (Note: It has an * explicit check for finding a new {@link com.oracle.max.graal.compiler.ir.BlockBegin} before a {@link com.oracle.max.graal.compiler.ir.BlockEnd} but * {@link com.oracle.max.graal.compiler.graph.BlockMap#moveSuccessorLists} has a similar check so this may be redundant). For example, @@ -137,7 +137,7 @@ * * * The {@code iconst_0} bytecode causes a {@link com.oracle.max.graal.compiler.ir.Constant} node representing zero to be pushed on the - * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} stack and the node to be appended to the {@link com.oracle.max.graal.compiler.ir.BlockBegin} (entry) node associated with index 0. + * {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase#curState} stack and the node to be appended to the {@link com.oracle.max.graal.compiler.ir.BlockBegin} (entry) node associated with index 0. * The {@code istore_2} causes the node to be popped of the stack and stored in the local slot 2. No IR node is * generated for the {@code istore_2}. The {@code goto} creates a {@link com.oracle.max.graal.compiler.ir.Goto} node which is a subclass * of {@link com.oracle.max.graal.compiler.ir.BlockEnd}, so this terminates the iteration. As part of termination the {@link com.oracle.max.graal.compiler.ir.Goto} node is marked as the diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/And.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/And.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/And.java Wed Jun 08 13:06:45 2011 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.max.graal.compiler.ir; -import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatDiv.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatDiv.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatDiv.java Wed Jun 08 13:06:45 2011 +0200 @@ -51,8 +51,7 @@ @Override public Node copy(Graph into) { - FloatDiv x = new FloatDiv(kind, null, null, isStrictFP(), into); - return x; + return new FloatDiv(kind, null, null, isStrictFP(), into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatMul.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatMul.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatMul.java Wed Jun 08 13:06:45 2011 +0200 @@ -51,8 +51,7 @@ @Override public Node copy(Graph into) { - FloatMul x = new FloatMul(kind, null, null, isStrictFP(), into); - return x; + return new FloatMul(kind, null, null, isStrictFP(), into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatRem.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatRem.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatRem.java Wed Jun 08 13:06:45 2011 +0200 @@ -51,8 +51,7 @@ @Override public Node copy(Graph into) { - FloatRem x = new FloatRem(kind, null, null, isStrictFP(), into); - return x; + return new FloatRem(kind, null, null, isStrictFP(), into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatSub.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatSub.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatSub.java Wed Jun 08 13:06:45 2011 +0200 @@ -40,8 +40,7 @@ @Override public Node copy(Graph into) { - FloatSub x = new FloatSub(kind, null, null, isStrictFP(), into); - return x; + return new FloatSub(kind, null, null, isStrictFP(), into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java Wed Jun 08 13:06:45 2011 +0200 @@ -114,6 +114,6 @@ @Override public Node copy(Graph into) { - return new If(compare(), into); + return new If(null, into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerAdd.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerAdd.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerAdd.java Wed Jun 08 13:06:45 2011 +0200 @@ -35,8 +35,7 @@ @Override public Node copy(Graph into) { - IntegerAdd x = new IntegerAdd(kind, null, null, into); - return x; + return new IntegerAdd(kind, null, null, into); } @Override diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerDiv.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerDiv.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerDiv.java Wed Jun 08 13:06:45 2011 +0200 @@ -40,8 +40,7 @@ @Override public Node copy(Graph into) { - IntegerDiv x = new IntegerDiv(kind, null, null, into); - return x; + return new IntegerDiv(kind, null, null, into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerMul.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerMul.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerMul.java Wed Jun 08 13:06:45 2011 +0200 @@ -40,8 +40,7 @@ @Override public Node copy(Graph into) { - IntegerMul x = new IntegerMul(kind, null, null, into); - return x; + return new IntegerMul(kind, null, null, into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerRem.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerRem.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerRem.java Wed Jun 08 13:06:45 2011 +0200 @@ -40,8 +40,7 @@ @Override public Node copy(Graph into) { - IntegerRem x = new IntegerRem(kind, null, null, into); - return x; + return new IntegerRem(kind, null, null, into); } } diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerSub.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerSub.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/IntegerSub.java Wed Jun 08 13:06:45 2011 +0200 @@ -35,8 +35,7 @@ @Override public Node copy(Graph into) { - IntegerSub x = new IntegerSub(kind, null, null, into); - return x; + return new IntegerSub(kind, null, null, into); } @Override diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Or.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Or.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Or.java Wed Jun 08 13:06:45 2011 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.max.graal.compiler.ir; -import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Xor.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Xor.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Xor.java Wed Jun 08 13:06:45 2011 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.max.graal.compiler.ir; -import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.compiler.phases.CanonicalizerPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/opt/CanonicalizerPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/opt/CanonicalizerPhase.java Wed Jun 08 13:04:17 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.opt; - -import java.util.*; - -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.graph.*; - -public class CanonicalizerPhase extends Phase { - - - @Override - protected void run(Graph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - List nodes = new ArrayList(graph.getNodes()); - for (Node n : nodes) { - if (n == null) { - continue; - } - if (!visited.isMarked(n)) { - this.canonicalize(n, visited); - } - } - } - - private void canonicalize(Node n, NodeBitMap visited) { - visited.mark(n); - for (Node input : n.inputs()) { - if (input == null) { - continue; - } - if (!visited.isNew(input) && !visited.isMarked(input)) { - canonicalize(input, visited); - } - } - - CanonicalizerOp op = n.lookup(CanonicalizerOp.class); - if (op != null) { - Node canonical = op.canonical(n); - if (canonical != n) { - n.replace(canonical); - C1XMetrics.NodesCanonicalized++; - } - } - } - - public interface CanonicalizerOp extends Op { - Node canonical(Node node); - } -} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/package-info.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/package-info.java Wed Jun 08 13:06:45 2011 +0200 @@ -86,7 +86,7 @@ * the IR graph prevent many bugs due to the mutability of {@code FrameState}. * *
  • - * Move the {@code FrameState} class to an inner class, or combine entirely, with the {@link com.oracle.max.graal.compiler.graph.GraphBuilder} class. After + * Move the {@code FrameState} class to an inner class, or combine entirely, with the {@link com.oracle.max.graal.compiler.phases.GraphBuilderPhase} class. After * the introduction of the {@code FrameStateInfo} into HIR nodes, the mutable value stack should only need to be * accessed from the graph builder.
  • * diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.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/CanonicalizerPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,71 @@ +/* + * 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 com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.graph.*; + +public class CanonicalizerPhase extends Phase { + + + @Override + protected void run(Graph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + List nodes = new ArrayList(graph.getNodes()); + for (Node n : nodes) { + if (n == null) { + continue; + } + if (!visited.isMarked(n)) { + this.canonicalize(n, visited); + } + } + } + + private void canonicalize(Node n, NodeBitMap visited) { + visited.mark(n); + for (Node input : n.inputs()) { + if (input == null) { + continue; + } + if (!visited.isNew(input) && !visited.isMarked(input)) { + canonicalize(input, visited); + } + } + + CanonicalizerOp op = n.lookup(CanonicalizerOp.class); + if (op != null) { + Node canonical = op.canonical(n); + if (canonical != n) { + n.replace(canonical); + C1XMetrics.NodesCanonicalized++; + } + } + } + + public interface CanonicalizerOp extends Op { + Node canonical(Node node); + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.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/DeadCodeEliminationPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,133 @@ +/* + * 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 com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; + + +public class DeadCodeEliminationPhase extends Phase { + + private NodeBitMap alive; + private NodeWorklist worklist; + private Graph graph; + + public int deletedNodeCount; + + @Override + protected void run(Graph graph) { + this.graph = graph; + this.alive = graph.createNodeBitMap(); + this.worklist = graph.createNodeWorklist(); + + worklist.add(graph.start()); + + iterateSuccessors(); + disconnectCFGNodes(); + + iterateInputs(); + disconnectNonCFGNodes(); + + deleteCFGNodes(); + deleteNonCFGNodes(); + + new PhiSimplifier(graph); + + if (C1XOptions.TraceDeadCodeElimination) { + System.out.printf("dead code elimination: deleted %d nodes\n", deletedNodeCount); + } + } + + private static boolean isCFG(Node n) { + return n != null && ((n instanceof Instruction) || n == n.graph().start()); + } + + private void iterateSuccessors() { + for (Node current : worklist) { + for (Node successor : current.successors()) { + worklist.add(successor); + } + } + } + + private void disconnectCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { + // iterate backwards so that the predecessor indexes in removePhiPredecessor are correct + for (int i = node.successors().size() - 1; i >= 0; i--) { + Node successor = node.successors().get(i); + if (successor != Node.Null && worklist.isMarked(successor)) { + if (successor instanceof Merge) { + ((Merge) successor).removePhiPredecessor(node); + } + } + } + node.successors().clearAll(); + node.inputs().clearAll(); + } + } + } + + private void deleteCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { + node.delete(); + deletedNodeCount++; + } + } + } + + private void iterateInputs() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && worklist.isMarked(node)) { + for (Node input : node.inputs()) { + worklist.add(input); + } + } + } + for (Node current : worklist) { + for (Node input : current.inputs()) { + worklist.add(input); + } + } + } + + private void disconnectNonCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { + node.inputs().clearAll(); + } + } + } + + private void deleteNonCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { + node.delete(); + deletedNodeCount++; + } + } + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DuplicationPhase.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/DuplicationPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, 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 com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.graph.*; + +/** + * Duplicates every node in the graph to test the implementation of the {@link com.oracle.max.graal.graph.Node#copy()} method in node subclasses. + */ +public class DuplicationPhase extends Phase { + + @Override + protected void run(Graph graph) { + + // Create duplicate graph. + CompilerGraph duplicate = new CompilerGraph(); + Map replacements = new HashMap(); + replacements.put(graph.start(), duplicate.start()); + duplicate.addDuplicate(graph.getNodes(), replacements); + + // Delete nodes in original graph. + for (Node n : graph.getNodes()) { + if (n != null && n != graph.start()) { + n.forceDelete(); + } + } + + // Copy nodes from duplicate back to original graph. + replacements.clear(); + replacements.put(duplicate.start(), graph.start()); + graph.addDuplicate(duplicate.getNodes(), replacements); + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.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/GraphBuilderPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,1553 @@ +/* + * Copyright (c) 2009, 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 static com.sun.cri.bytecode.Bytecodes.*; +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.graph.BlockMap.*; +import com.oracle.max.graal.compiler.graph.BlockMap.Block; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.*; +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.*; +import com.sun.cri.ri.RiType.*; + +/** + * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. + * A number of optimizations may be performed during parsing of the bytecode, including value + * numbering, inlining, constant folding, strength reduction, etc. + */ +public final class GraphBuilderPhase extends Phase { + + /** + * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace + * the bytecode instructions as they are parsed. + */ + public static final int TRACELEVEL_INSTRUCTIONS = 1; + + /** + * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace + * the frame state before each bytecode instruction as it is parsed. + */ + public static final int TRACELEVEL_STATE = 2; + + private final C1XCompilation compilation; + private 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 FrameStateBuilder frameState; // the current execution state + + // bci-to-block mapping + private Block[] blockFromBci; + private ArrayList blockList; + + private int nextBlockNumber; + + private Value methodSynchronizedObject; + private CiExceptionHandler syncHandler; + + private Block unwindBlock; + private Block returnBlock; + + // 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) { + return o1.blockID - o2.blockID; + } + }); + + private Instruction lastInstr; // the last instruction added + + private final Set blocksOnWorklist = new HashSet(); + private final Set blocksVisited = new HashSet(); + + private final boolean createUnwind; + + + /** + * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. + * + * @param compilation the compilation + * @param ir the IR to build the graph into + * @param graph + */ + public GraphBuilderPhase(C1XCompilation compilation, RiMethod method, boolean createUnwind) { + this.compilation = compilation; + + this.runtime = compilation.runtime; + this.method = method; + this.stats = compilation.stats; + this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; + this.stream = new BytecodeStream(method.code()); + + this.constantPool = runtime.getConstantPool(method); + this.createUnwind = createUnwind; + } + + @Override + protected void run(Graph graph) { + assert graph != null; + this.graph = (CompilerGraph) graph; + this.frameState = new FrameStateBuilder(method, graph); + build(); + } + + /** + * Builds the graph for a the specified {@code IRScope}. + * + * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception + * handler and the method is not synchronized + */ + private void build() { + if (log != null) { + log.println(); + log.println("Compiling " + method); + } + + // 2. compute the block map, setup exception handlers and get the entrypoint(s) + BlockMap blockMap = compilation.getBlockMap(method); + + blockList = new ArrayList(blockMap.blocks); + blockFromBci = new Block[method.code().length]; + for (int i = 0; i < blockList.size(); i++) { + int blockID = nextBlockNumber(); + assert blockID == i; + Block block = blockList.get(i); + if (block.startBci >= 0) { + blockFromBci[block.startBci] = block; + } + } + + // 1. create the start block + Block startBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI); + markOnWorkList(startBlock); + lastInstr = createTarget(startBlock, frameState); + graph.start().setStart(lastInstr); + + if (isSynchronized(method.accessFlags())) { + // 4A.1 add a monitor enter to the start block + 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, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); + } else { + // 4B.1 simply finish the start block + finishStartBlock(startBlock); + + if (createUnwind) { + syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); + } + } + + // 5. SKIPPED: look for intrinsics + + // 6B.1 do the normal parsing + addToWorkList(blockFromBci[0]); + iterateAllBlocks(); + + // remove Placeholders + for (Node n : graph.getNodes()) { + if (n instanceof Placeholder) { + Placeholder p = (Placeholder) n; + assert p.blockPredecessors().size() == 1; + Node pred = p.blockPredecessors().get(0); + int predIndex = p.predecessorsIndex().get(0); + pred.successors().setAndClear(predIndex, p, 0); + p.delete(); + } + } + + // 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 (delete) { + n.delete(); + } + } + } + } + + private int nextBlockNumber() { + stats.blockCount++; + return nextBlockNumber++; + } + + private Block nextBlock(int bci) { + Block block = new Block(); + block.startBci = bci; + block.endBci = bci; + block.blockID = nextBlockNumber(); + return block; + } + + private Block unwindBlock() { + if (unwindBlock == null) { + unwindBlock = new Block(); + unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + unwindBlock.blockID = nextBlockNumber(); + addToWorkList(unwindBlock); + } + return unwindBlock; + } + + private Block returnBlock() { + if (returnBlock == null) { + returnBlock = new Block(); + returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + returnBlock.blockID = nextBlockNumber(); + addToWorkList(returnBlock); + } + return returnBlock; + } + + private void markOnWorkList(Block block) { + blocksOnWorklist.add(block); + } + + private boolean isOnWorkList(Block block) { + return blocksOnWorklist.contains(block); + } + + private void markVisited(Block block) { + blocksVisited.add(block); + } + + private boolean isVisited(Block block) { + return blocksVisited.contains(block); + } + + private void finishStartBlock(Block startBlock) { + assert bci() == 0; + Instruction target = createTargetAt(0, frameState); + appendGoto(target); + } + + public void mergeOrClone(Block target, FrameStateAccess newState) { + Instruction first = target.firstInstruction; + if (target.isLoopHeader && isVisited(target)) { + first = ((LoopBegin) first).loopEnd(); + } + assert first instanceof StateSplit; + + int bci = target.startBci; + + FrameState existingState = ((StateSplit) first).stateBefore(); + + if (existingState == null) { + // copy state because it is modified + FrameState duplicate = newState.duplicate(bci); + + // if the block is a loop header, insert all necessary phis + if (first instanceof LoopBegin && target.isLoopHeader) { + assert first instanceof Merge; + insertLoopPhis((Merge) first, duplicate); + ((Merge) first).setStateBefore(duplicate); + } else { + ((StateSplit) first).setStateBefore(duplicate); + } + } else { + if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { + // stacks or locks do not match--bytecodes would not verify + TTY.println(existingState.toString()); + TTY.println(newState.duplicate(0).toString()); + throw new CiBailout("stack or locks do not match"); + } + assert existingState.localsSize() == newState.localsSize(); + assert existingState.stackSize() == newState.stackSize(); + + if (first instanceof Placeholder) { + assert !target.isLoopHeader; + Merge merge = new Merge(graph); + + Placeholder p = (Placeholder) first; + assert p.next() == null; + p.replace(merge); + target.firstInstruction = merge; + merge.setStateBefore(existingState); + first = merge; + } + + existingState.merge((Merge) first, newState); + } + + for (int j = 0; j < frameState.localsSize() + frameState.stackSize(); ++j) { + if (frameState.valueAt(j) != null) { + assert !frameState.valueAt(j).isDeleted(); + } + } + } + + private void insertLoopPhis(Merge merge, FrameState newState) { + int stackSize = newState.stackSize(); + for (int i = 0; i < stackSize; i++) { + // always insert phis for the stack + Value x = newState.stackAt(i); + if (x != null) { + newState.setupPhiForStack(merge, i).addInput(x); + } + } + int localsSize = newState.localsSize(); + for (int i = 0; i < localsSize; i++) { + Value x = newState.localAt(i); + if (x != null) { + newState.setupPhiForLocal(merge, i).addInput(x); + } + } + } + + public BytecodeStream stream() { + return stream; + } + + public int bci() { + return stream.currentBCI(); + } + + private void loadLocal(int index, CiKind kind) { + frameState.push(kind, frameState.loadLocal(index)); + } + + private void storeLocal(CiKind kind, int index) { + frameState.storeLocal(index, frameState.pop(kind)); + } + + public boolean covers(RiExceptionHandler handler, int bci) { + return handler.startBCI() <= bci && bci < handler.endBCI(); + } + + public boolean isCatchAll(RiExceptionHandler handler) { + return handler.catchTypeCPI() == 0; + } + + private Instruction handleException(Value exceptionObject, int bci) { + assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; + + RiExceptionHandler firstHandler = null; + RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); + // join with all potential exception handlers + if (exceptionHandlers != null) { + for (RiExceptionHandler handler : exceptionHandlers) { + // if the handler covers this bytecode index, add it to the list + if (covers(handler, bci)) { + firstHandler = handler; + break; + } + } + } + + if (firstHandler == null) { + firstHandler = syncHandler; + } + + if (firstHandler != null) { + compilation.setHasExceptionHandlers(); + + Block dispatchBlock = null; + for (Block block : blockList) { + if (block instanceof ExceptionBlock) { + ExceptionBlock excBlock = (ExceptionBlock) block; + if (excBlock.handler == firstHandler) { + dispatchBlock = block; + break; + } + } + } + // if there's no dispatch block then the catch block needs to be a catch all + if (dispatchBlock == null) { + assert isCatchAll(firstHandler); + int handlerBCI = firstHandler.handlerBCI(); + if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) { + dispatchBlock = unwindBlock(); + } else { + dispatchBlock = blockFromBci[handlerBCI]; + } + } + FrameState entryState = frameState.duplicateWithEmptyStack(bci); + + StateSplit entry = new Placeholder(graph); + entry.setStateBefore(entryState); + + Instruction currentNext = entry; + Value currentExceptionObject = exceptionObject; + if (currentExceptionObject == null) { + ExceptionObject exception = new ExceptionObject(graph); + entry.setNext(exception); + currentNext = exception; + currentExceptionObject = exception; + } + FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, currentExceptionObject); + + Instruction successor = createTarget(dispatchBlock, stateWithException); + currentNext.setNext(successor); + return entry; + } + return null; + } + + private void genLoadConstant(int cpi) { + Object con = constantPool.lookupConstant(cpi); + + if (con instanceof RiType) { + // this is a load of class constant which might be unresolved + RiType riType = (RiType) con; + if (!riType.isResolved()) { + append(new Deoptimize(graph)); + frameState.push(CiKind.Object, append(Constant.forObject(null, graph))); + } else { + frameState.push(CiKind.Object, append(new Constant(riType.getEncoding(Representation.JavaClass), graph))); + } + } else if (con instanceof CiConstant) { + CiConstant constant = (CiConstant) con; + frameState.push(constant.kind.stackKind(), appendConstant(constant)); + } else { + throw new Error("lookupConstant returned an object of incorrect type"); + } + } + + private void genLoadIndexed(CiKind kind) { + Value index = frameState.ipop(); + Value array = frameState.apop(); + Value length = append(new ArrayLength(array, graph)); + Value v = append(new LoadIndexed(array, index, length, kind, graph)); + frameState.push(kind.stackKind(), v); + } + + private void genStoreIndexed(CiKind kind) { + Value value = frameState.pop(kind.stackKind()); + Value index = frameState.ipop(); + Value array = frameState.apop(); + Value length = append(new ArrayLength(array, graph)); + StoreIndexed result = new StoreIndexed(array, index, length, kind, value, graph); + append(result); + } + + private void stackOp(int opcode) { + switch (opcode) { + case POP: { + frameState.xpop(); + break; + } + case POP2: { + frameState.xpop(); + frameState.xpop(); + break; + } + case DUP: { + Value w = frameState.xpop(); + frameState.xpush(w); + frameState.xpush(w); + break; + } + case DUP_X1: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP_X2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X1: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + Value w4 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w4); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case SWAP: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + break; + } + default: + throw Util.shouldNotReachHere(); + } + + } + + private void genArithmeticOp(CiKind kind, int opcode) { + genArithmeticOp(kind, opcode, false); + } + + private void genArithmeticOp(CiKind result, int opcode, boolean canTrap) { + Value y = frameState.pop(result); + Value x = frameState.pop(result); + boolean isStrictFP = isStrict(method.accessFlags()); + Arithmetic v; + switch(opcode){ + case IADD: + case LADD: v = new IntegerAdd(result, x, y, graph); break; + case FADD: + case DADD: v = new FloatAdd(result, x, y, isStrictFP, graph); break; + case ISUB: + case LSUB: v = new IntegerSub(result, x, y, graph); break; + case FSUB: + case DSUB: v = new FloatSub(result, x, y, isStrictFP, graph); break; + case IMUL: + case LMUL: v = new IntegerMul(result, x, y, graph); break; + case FMUL: + case DMUL: v = new FloatMul(result, x, y, isStrictFP, graph); break; + case IDIV: + case LDIV: v = new IntegerDiv(result, x, y, graph); break; + case FDIV: + case DDIV: v = new FloatDiv(result, x, y, isStrictFP, graph); break; + case IREM: + case LREM: v = new IntegerRem(result, x, y, graph); break; + case FREM: + case DREM: v = new FloatRem(result, x, y, isStrictFP, graph); break; + default: + throw new CiBailout("should not reach"); + } + Value result1 = append(v); + if (canTrap) { + append(new ValueAnchor(result1, graph)); + } + frameState.push(result, result1); + } + + private void genNegateOp(CiKind kind) { + frameState.push(kind, append(new Negate(frameState.pop(kind), graph))); + } + + private void genShiftOp(CiKind kind, int opcode) { + Value s = frameState.ipop(); + Value x = frameState.pop(kind); + Shift v; + switch(opcode){ + case ISHL: + case LSHL: v = new LeftShift(kind, x, s, graph); break; + case ISHR: + case LSHR: v = new RightShift(kind, x, s, graph); break; + case IUSHR: + case LUSHR: v = new UnsignedRightShift(kind, x, s, graph); break; + default: + throw new CiBailout("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genLogicOp(CiKind kind, int opcode) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + Logic v; + switch(opcode){ + case IAND: + case LAND: v = new And(kind, x, y, graph); break; + case IOR: + case LOR: v = new Or(kind, x, y, graph); break; + case IXOR: + case LXOR: v = new Xor(kind, x, y, graph); break; + default: + throw new CiBailout("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genCompareOp(CiKind kind, int opcode, CiKind resultKind) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + Value value = append(new NormalizeCompare(opcode, resultKind, x, y, graph)); + if (!resultKind.isVoid()) { + frameState.ipush(value); + } + } + + private void genConvert(int opcode, CiKind from, CiKind to) { + CiKind tt = to.stackKind(); + frameState.push(tt, append(new Convert(opcode, frameState.pop(from.stackKind()), tt, graph))); + } + + private void genIncrement() { + int index = stream().readLocalIndex(); + int delta = stream().readIncrement(); + Value x = frameState.localAt(index); + Value y = append(Constant.forInt(delta, graph)); + frameState.storeLocal(index, append(new IntegerAdd(CiKind.Int, x, y, graph))); + } + + private void genGoto(int fromBCI, int toBCI) { + appendGoto(createTargetAt(toBCI, frameState)); + } + + private void ifNode(Value x, Condition cond, Value y) { + assert !x.isDeleted() && !y.isDeleted(); + If ifNode = new If(new Compare(x, cond, y, graph), graph); + append(ifNode); + Instruction tsucc = createTargetAt(stream().readBranchDest(), frameState); + ifNode.setBlockSuccessor(0, tsucc); + Instruction fsucc = createTargetAt(stream().nextBCI(), frameState); + ifNode.setBlockSuccessor(1, fsucc); + } + + private void genIfZero(Condition cond) { + Value y = appendConstant(CiConstant.INT_0); + Value x = frameState.ipop(); + ifNode(x, cond, y); + } + + private void genIfNull(Condition cond) { + Value y = appendConstant(CiConstant.NULL_OBJECT); + Value x = frameState.apop(); + ifNode(x, cond, y); + } + + private void genIfSame(CiKind kind, Condition cond) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + assert !x.isDeleted() && !y.isDeleted(); + ifNode(x, cond, y); + } + + private void genThrow(int bci) { + Value exception = frameState.apop(); + append(new NullCheck(exception, graph)); + + Instruction entry = handleException(exception, bci); + if (entry != null) { + append(entry); + } else { + frameState.clearStack(); + frameState.apush(exception); + appendGoto(createTarget(unwindBlock(), frameState)); + } + } + + private void genCheckCast() { + int cpi = stream().readCPI(); + RiType type = constantPool.lookupType(cpi, CHECKCAST); + boolean isInitialized = type.isResolved(); + Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Value object = frameState.apop(); + if (typeInstruction != null) { + frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); + } else { + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genInstanceOf() { + int cpi = stream().readCPI(); + RiType type = constantPool.lookupType(cpi, INSTANCEOF); + boolean isInitialized = type.isResolved(); + Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Value object = frameState.apop(); + if (typeInstruction != null) { + frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); + } else { + frameState.ipush(appendConstant(CiConstant.INT_0)); + } + } + + void genNewInstance(int cpi) { + RiType type = constantPool.lookupType(cpi, NEW); + if (type.isResolved()) { + NewInstance n = new NewInstance(type, cpi, constantPool, graph); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genNewTypeArray(int typeCode) { + CiKind kind = CiKind.fromArrayTypeCode(typeCode); + 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); + Value length = frameState.ipop(); + if (type.isResolved()) { + NewArray n = new NewObjectArray(type, length, graph); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + + } + + private void genNewMultiArray(int cpi) { + 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); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genGetField(int cpi, RiField field) { + CiKind kind = field.kind(); + Value receiver = frameState.apop(); + if (field.isResolved()) { + LoadField load = new LoadField(receiver, field, graph); + appendOptimizedLoadField(kind, load); + } else { + append(new Deoptimize(graph)); + frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); + } + } + + private void genPutField(int cpi, RiField field) { + Value value = frameState.pop(field.kind().stackKind()); + Value receiver = frameState.apop(); + if (field.isResolved()) { + StoreField store = new StoreField(receiver, field, value, graph); + appendOptimizedStoreField(store); + } else { + append(new Deoptimize(graph)); + } + } + + private void genGetStatic(int cpi, RiField field) { + RiType holder = field.holder(); + boolean isInitialized = field.isResolved(); + CiConstant constantValue = null; + if (isInitialized) { + constantValue = field.constantValue(null); + } + if (constantValue != null) { + frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue)); + } else { + Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); + CiKind kind = field.kind(); + if (container != null) { + LoadField load = new LoadField(container, field, graph); + appendOptimizedLoadField(kind, load); + } else { + append(new Deoptimize(graph)); + frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); + } + } + } + + private void genPutStatic(int cpi, RiField field) { + RiType holder = field.holder(); + Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi); + Value value = frameState.pop(field.kind().stackKind()); + if (container != null) { + StoreField store = new StoreField(container, field, value, graph); + appendOptimizedStoreField(store); + } else { + append(new Deoptimize(graph)); + } + } + + private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { + if (initialized) { + return appendConstant(holder.getEncoding(representation)); + } else { + append(new Deoptimize(graph)); + return null; + } + } + + private void appendOptimizedStoreField(StoreField store) { + append(store); + } + + private void appendOptimizedLoadField(CiKind kind, LoadField load) { + // append the load to the instruction + Value optimized = append(load); + frameState.push(kind.stackKind(), optimized); + } + + private void genInvokeStatic(RiMethod target, int cpi, RiConstantPool constantPool) { + RiType holder = target.holder(); + boolean isInitialized = target.isResolved() && holder.isInitialized(); + if (!isInitialized && C1XOptions.ResolveClassBeforeStaticInvoke) { + // Re-use the same resolution code as for accessing a static field. Even though + // the result of resolution is not used by the invocation (only the side effect + // of initialization is required), it can be commoned with static field accesses. + genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); + } + Value[] args = frameState.popArguments(target.signature().argumentSlots(false)); + appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); + } + + private void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool); + + } + + private void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool); + + } + + private void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + invokeDirect(target, args, knownHolder, cpi, constantPool); + + } + + private void genInvokeIndirect(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { + Value receiver = args[0]; + // attempt to devirtualize the call + if (target.isResolved()) { + RiType klass = target.holder(); + + // 0. check for trivial cases + if (target.canBeStaticallyBound() && !isAbstract(target.accessFlags())) { + // check for trivial cases (e.g. final methods, nonvirtual methods) + invokeDirect(target, args, target.holder(), cpi, constantPool); + return; + } + // 1. check if the exact type of the receiver can be determined + RiType exact = getExactType(klass, receiver); + if (exact != null && exact.isResolved()) { + // either the holder class is exact, or the receiver object has an exact type + invokeDirect(exact.resolveMethodImpl(target), args, exact, cpi, constantPool); + return; + } + } + // devirtualization failed, produce an actual invokevirtual + appendInvoke(opcode, target, args, cpi, constantPool); + } + + private CiKind returnKind(RiMethod target) { + return target.signature().returnKind(); + } + + private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { + appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); + } + + 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(method.holder()), graph); + Value result = appendWithBCI(invoke); + invoke.setExceptionEdge(handleException(null, bci())); + frameState.pushReturn(resultType, result); + } + + private RiType getExactType(RiType staticType, Value receiver) { + RiType exact = staticType.exactType(); + if (exact == null) { + exact = receiver.exactType(); + if (exact == null) { + if (receiver.isConstant()) { + exact = runtime.getTypeOf(receiver.asConstant()); + } + if (exact == null) { + RiType declared = receiver.declaredType(); + exact = declared == null || !declared.isResolved() ? null : declared.exactType(); + } + } + } + return exact; + } + + private void callRegisterFinalizer() { + Value receiver = frameState.loadLocal(0); + RiType declaredType = receiver.declaredType(); + RiType receiverType = declaredType; + RiType exactType = receiver.exactType(); + if (exactType == null && declaredType != null) { + exactType = declaredType.exactType(); + } + 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 = method.holder(); + exactType = receiverType.exactType(); + } + boolean needsCheck = true; + if (exactType != null) { + // we have an exact type + needsCheck = exactType.hasFinalizer(); + } else { + // if either the declared type of receiver or the holder can be assumed to have no finalizers + if (declaredType != null && !declaredType.hasFinalizableSubclass()) { + if (compilation.recordNoFinalizableSubclassAssumption(declaredType)) { + needsCheck = false; + } + } + + if (receiverType != null && !receiverType.hasFinalizableSubclass()) { + if (compilation.recordNoFinalizableSubclassAssumption(receiverType)) { + needsCheck = false; + } + } + } + + if (needsCheck) { + // append a call to the finalizer registration + append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph)); + C1XMetrics.InlinedFinalizerChecks++; + } + } + + private void genReturn(Value x) { + frameState.clearStack(); + if (x != null) { + frameState.push(x.kind, x); + } + appendGoto(createTarget(returnBlock(), frameState)); + } + + private void genMonitorEnter(Value x, int bci) { + int lockNumber = frameState.locksSize(); + MonitorAddress lockAddress = null; + if (runtime.sizeOfBasicObjectLock() != 0) { + lockAddress = new MonitorAddress(lockNumber, graph); + append(lockAddress); + } + MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); + appendWithBCI(monitorEnter); + frameState.lock(x); + if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { + monitorEnter.setStateAfter(frameState.create(0)); + } + } + + private void genMonitorExit(Value x) { + int lockNumber = frameState.locksSize() - 1; + if (lockNumber < 0) { + throw new CiBailout("monitor stack underflow"); + } + MonitorAddress lockAddress = null; + if (runtime.sizeOfBasicObjectLock() != 0) { + lockAddress = new MonitorAddress(lockNumber, graph); + append(lockAddress); + } + appendWithBCI(new MonitorExit(x, lockAddress, lockNumber, graph)); + frameState.unlock(); + } + + private void genJsr(int dest) { + throw new CiBailout("jsr/ret not supported"); + } + + private void genRet(int localIndex) { + throw new CiBailout("jsr/ret not supported"); + } + + private void genTableswitch() { + int bci = bci(); + Value value = frameState.ipop(); + BytecodeTableSwitch ts = new BytecodeTableSwitch(stream(), bci); + int max = ts.numberOfCases(); + List list = new ArrayList(max + 1); + List offsetList = new ArrayList(max + 1); + for (int i = 0; i < max; i++) { + // add all successors to the successor list + int offset = ts.offsetAt(i); + list.add(null); + offsetList.add(offset); + } + int offset = ts.defaultOffset(); + list.add(null); + offsetList.add(offset); + TableSwitch tableSwitch = new TableSwitch(value, list, ts.lowKey(), graph); + for (int i = 0; i < offsetList.size(); ++i) { + tableSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); + } + append(tableSwitch); + } + + private void genLookupswitch() { + int bci = bci(); + Value value = frameState.ipop(); + BytecodeLookupSwitch ls = new BytecodeLookupSwitch(stream(), bci); + int max = ls.numberOfCases(); + List list = new ArrayList(max + 1); + List offsetList = new ArrayList(max + 1); + int[] keys = new int[max]; + for (int i = 0; i < max; i++) { + // add all successors to the successor list + int offset = ls.offsetAt(i); + list.add(null); + offsetList.add(offset); + keys[i] = ls.keyAt(i); + } + int offset = ls.defaultOffset(); + list.add(null); + offsetList.add(offset); + LookupSwitch lookupSwitch = new LookupSwitch(value, list, keys, graph); + for (int i = 0; i < offsetList.size(); ++i) { + lookupSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); + } + append(lookupSwitch); + } + + private Value appendConstant(CiConstant constant) { + return append(new Constant(constant, graph)); + } + + private Value append(Instruction x) { + return appendWithBCI(x); + } + + private Value append(Value v) { + return v; + } + + private Value appendWithBCI(Instruction x) { + assert x.predecessors().size() == 0 : "instruction should not have been appended yet"; + assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; + lastInstr.setNext(x); + + lastInstr = x; + if (++stats.nodeCount >= C1XOptions.MaximumInstructionCount) { + // bailout if we've exceeded the maximum inlining size + throw new CiBailout("Method and/or inlining is too large"); + } + + return x; + } + + private Instruction createTargetAt(int bci, FrameStateAccess stateAfter) { + return createTarget(blockFromBci[bci], stateAfter); + } + + private Instruction createTarget(Block block, FrameStateAccess stateAfter) { + assert block != null && stateAfter != null; + assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : "non-loop block must be iterated after all its predecessors"; + + if (block.isExceptionEntry) { + assert stateAfter.stackSize() == 1; + } + + if (block.firstInstruction == null) { + if (block.isLoopHeader) { +// block.firstInstruction = new Merge(block.startBci, graph); + + LoopBegin loopBegin = new LoopBegin(graph); + LoopEnd loopEnd = new LoopEnd(graph); + loopEnd.setLoopBegin(loopBegin); + block.firstInstruction = loopBegin; + } else { + block.firstInstruction = new Placeholder(graph); + } + } + mergeOrClone(block, stateAfter); + addToWorkList(block); + + if (block.firstInstruction instanceof LoopBegin && isVisited(block)) { + return ((LoopBegin) block.firstInstruction).loopEnd(); + } else { + return block.firstInstruction; + } + } + + private Value synchronizedObject(FrameStateAccess state, RiMethod target) { + if (isStatic(target.accessFlags())) { + Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph); + return append(classConstant); + } else { + return state.localAt(0); + } + } + + private void iterateAllBlocks() { + Block block; + while ((block = removeFromWorkList()) != null) { + + // remove blocks that have no predecessors by the time it their bytecodes are parsed + if (block.firstInstruction == null) { + markVisited(block); + continue; + } + + if (!isVisited(block)) { + markVisited(block); + // now parse the block + frameState.initializeFrom(((StateSplit) block.firstInstruction).stateBefore()); + lastInstr = block.firstInstruction; + assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID; + + if (block == returnBlock) { + createReturnBlock(block); + } else if (block == unwindBlock) { + createUnwindBlock(block); + } else if (block instanceof ExceptionBlock) { + createExceptionDispatch((ExceptionBlock) block); + } else { + iterateBytecodesForBlock(block); + } + } + } + for (Block b : blocksVisited) { + if (b.isLoopHeader) { + LoopBegin begin = (LoopBegin) b.firstInstruction; + LoopEnd end = begin.loopEnd(); + +// This can happen with degenerated loops like this one: +// for (;;) { +// try { +// break; +// } catch (UnresolvedException iioe) { +// } +// } + if (end.stateBefore() != null) { + begin.stateBefore().merge(begin, end.stateBefore()); + } else { + end.delete(); + Merge merge = new Merge(graph); + merge.successors().setAndClear(merge.nextIndex(), begin, begin.nextIndex()); + begin.replace(merge); + } + } + } + } + + private void createUnwindBlock(Block block) { + if (Modifier.isSynchronized(method.accessFlags())) { + genMonitorExit(methodSynchronizedObject); + } + append(graph.createUnwind(frameState.apop())); + } + + private void createReturnBlock(Block block) { + if (method.isConstructor() && method.holder().superType() == null) { + callRegisterFinalizer(); + } + 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(methodSynchronizedObject); + } + append(graph.createReturn(x)); + } + + private void createExceptionDispatch(ExceptionBlock block) { + if (block.handler == null) { + assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize(); + createUnwindBlock(block); + } else { + assert frameState.stackSize() == 1; + + Block nextBlock = block.next == null ? unwindBlock() : block.next; + if (block.handler.catchType().isResolved()) { + Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState); + Instruction nextDispatch = createTarget(nextBlock, frameState); + append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph)); + } else { + Deoptimize deopt = new Deoptimize(graph); + deopt.setMessage("unresolved " + block.handler.catchType().name()); + append(deopt); + Instruction nextDispatch = createTarget(nextBlock, frameState); + appendGoto(nextDispatch); + } + } + } + + private void appendGoto(Instruction target) { + lastInstr.setNext(target); + } + + private void iterateBytecodesForBlock(Block block) { + assert frameState != null; + + stream.setBCI(block.startBci); + + int endBCI = stream.endBCI(); + boolean blockStart = true; + + int bci = block.startBci; + while (bci < endBCI) { + Block nextBlock = blockFromBci[bci]; + if (nextBlock != null && nextBlock != block) { + assert !nextBlock.isExceptionEntry; + // we fell through to the next block, add a goto and break + appendGoto(createTarget(nextBlock, frameState)); + break; + } + // read the opcode + int opcode = stream.currentBC(); + + traceState(); + traceInstruction(bci, opcode, blockStart); + processBytecode(bci, opcode); + + if (Schedule.isBlockEnd(lastInstr) || lastInstr.next() != null) { + break; + } + + stream.next(); + bci = stream.currentBCI(); + if (lastInstr instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) lastInstr; + if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { + stateSplit.setStateAfter(frameState.create(bci)); + } + } + blockStart = false; + } + } + + 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)); + 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)); + } + for (int i = 0; i < frameState.stackSize(); ++i) { + Value value = frameState.stackAt(i); + log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); + } + for (int i = 0; i < frameState.locksSize(); ++i) { + Value value = frameState.lockAt(i); + log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); + } + } + } + + private void processBytecode(int bci, int opcode) { + int cpi; + + // Checkstyle: stop + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); break; + case ICONST_M1 : frameState.ipush(appendConstant(CiConstant.INT_MINUS_1)); break; + case ICONST_0 : frameState.ipush(appendConstant(CiConstant.INT_0)); break; + case ICONST_1 : frameState.ipush(appendConstant(CiConstant.INT_1)); break; + case ICONST_2 : frameState.ipush(appendConstant(CiConstant.INT_2)); break; + case ICONST_3 : frameState.ipush(appendConstant(CiConstant.INT_3)); break; + case ICONST_4 : frameState.ipush(appendConstant(CiConstant.INT_4)); break; + case ICONST_5 : frameState.ipush(appendConstant(CiConstant.INT_5)); break; + case LCONST_0 : frameState.lpush(appendConstant(CiConstant.LONG_0)); break; + case LCONST_1 : frameState.lpush(appendConstant(CiConstant.LONG_1)); break; + case FCONST_0 : frameState.fpush(appendConstant(CiConstant.FLOAT_0)); break; + case FCONST_1 : frameState.fpush(appendConstant(CiConstant.FLOAT_1)); break; + case FCONST_2 : frameState.fpush(appendConstant(CiConstant.FLOAT_2)); break; + case DCONST_0 : frameState.dpush(appendConstant(CiConstant.DOUBLE_0)); break; + case DCONST_1 : frameState.dpush(appendConstant(CiConstant.DOUBLE_1)); break; + case BIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI()); break; + case ILOAD : loadLocal(stream.readLocalIndex(), CiKind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), CiKind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), CiKind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), CiKind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), CiKind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, CiKind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, CiKind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, CiKind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, CiKind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, CiKind.Object); break; + case IALOAD : genLoadIndexed(CiKind.Int ); break; + case LALOAD : genLoadIndexed(CiKind.Long ); break; + case FALOAD : genLoadIndexed(CiKind.Float ); break; + case DALOAD : genLoadIndexed(CiKind.Double); break; + case AALOAD : genLoadIndexed(CiKind.Object); break; + case BALOAD : genLoadIndexed(CiKind.Byte ); break; + case CALOAD : genLoadIndexed(CiKind.Char ); break; + case SALOAD : genLoadIndexed(CiKind.Short ); break; + case ISTORE : storeLocal(CiKind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(CiKind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(CiKind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(CiKind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(CiKind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(CiKind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(CiKind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(CiKind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(CiKind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(CiKind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(CiKind.Int ); break; + case LASTORE : genStoreIndexed(CiKind.Long ); break; + case FASTORE : genStoreIndexed(CiKind.Float ); break; + case DASTORE : genStoreIndexed(CiKind.Double); break; + case AASTORE : genStoreIndexed(CiKind.Object); break; + case BASTORE : genStoreIndexed(CiKind.Byte ); break; + case CASTORE : genStoreIndexed(CiKind.Char ); break; + case SASTORE : genStoreIndexed(CiKind.Short ); break; + case POP : // fall through + case POP2 : // fall through + case DUP : // fall through + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(CiKind.Int, opcode); break; + case IDIV : // fall through + case IREM : genArithmeticOp(CiKind.Int, opcode, true); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(CiKind.Long, opcode); break; + case LDIV : // fall through + case LREM : genArithmeticOp(CiKind.Long, opcode, true); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(CiKind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(CiKind.Double, opcode); break; + case INEG : genNegateOp(CiKind.Int); break; + case LNEG : genNegateOp(CiKind.Long); break; + case FNEG : genNegateOp(CiKind.Float); break; + case DNEG : genNegateOp(CiKind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(CiKind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(CiKind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(CiKind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(CiKind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2L : genConvert(opcode, CiKind.Int , CiKind.Long ); break; + case I2F : genConvert(opcode, CiKind.Int , CiKind.Float ); break; + case I2D : genConvert(opcode, CiKind.Int , CiKind.Double); break; + case L2I : genConvert(opcode, CiKind.Long , CiKind.Int ); break; + case L2F : genConvert(opcode, CiKind.Long , CiKind.Float ); break; + case L2D : genConvert(opcode, CiKind.Long , CiKind.Double); break; + case F2I : genConvert(opcode, CiKind.Float , CiKind.Int ); break; + case F2L : genConvert(opcode, CiKind.Float , CiKind.Long ); break; + case F2D : genConvert(opcode, CiKind.Float , CiKind.Double); break; + case D2I : genConvert(opcode, CiKind.Double, CiKind.Int ); break; + case D2L : genConvert(opcode, CiKind.Double, CiKind.Long ); break; + case D2F : genConvert(opcode, CiKind.Double, CiKind.Float ); break; + case I2B : genConvert(opcode, CiKind.Int , CiKind.Byte ); break; + case I2C : genConvert(opcode, CiKind.Int , CiKind.Char ); break; + case I2S : genConvert(opcode, CiKind.Int , CiKind.Short ); break; + case LCMP : genCompareOp(CiKind.Long, opcode, CiKind.Int); break; + case FCMPL : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; + case FCMPG : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; + case DCMPL : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; + case DCMPG : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(CiKind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(CiKind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(CiKind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(CiKind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(CiKind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(CiKind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(frameState.peekKind(), Condition.EQ); break; + case IF_ACMPNE : genIfSame(frameState.peekKind(), Condition.NE); break; + case GOTO : genGoto(stream.currentBCI(), stream.readBranchDest()); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genTableswitch(); break; + case LOOKUPSWITCH : genLookupswitch(); break; + case IRETURN : genReturn(frameState.ipop()); break; + case LRETURN : genReturn(frameState.lpop()); break; + case FRETURN : genReturn(frameState.fpop()); break; + 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 NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(stream.currentBCI()); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.currentBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(stream.currentBCI(), stream.readFarBranchDest()); break; + case JSR_W : genJsr(stream.readFarBranchDest()); break; + case BREAKPOINT: + throw new CiBailout("concurrent setting of breakpoint"); + default: + throw new CiBailout("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); + } + // Checkstyle: resume + } + + private void traceInstruction(int bci, int opcode, boolean blockStart) { + if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_INSTRUCTIONS && !TTY.isSuppressed()) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + log.println(sb.toString()); + } + } + + private void genArrayLength() { + frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); + } + + /** + * 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 + * DFNs are earlier in the list). + * @param block the block to add to the work list + */ + private void addToWorkList(Block block) { + if (!isOnWorkList(block)) { + markOnWorkList(block); + sortIntoWorkList(block); + } + } + + private void sortIntoWorkList(Block top) { + workList.offer(top); + } + + /** + * Removes the next block from the worklist. The list is sorted topologically, so the + * block with the lowest depth first number in the list will be removed and returned. + * @return the next block from the worklist; {@code null} if there are no blocks + * in the worklist + */ + private Block removeFromWorkList() { + return workList.poll(); + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.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/InliningPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,285 @@ +/* + * 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.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +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 InliningPhase extends Phase { + + private final C1XCompilation compilation; + private final IR ir; + + private final Queue invokes = new ArrayDeque(); + private final Queue methods = new ArrayDeque(); + private int inliningSize; + + public InliningPhase(C1XCompilation compilation, IR ir) { + this.compilation = compilation; + this.ir = ir; + } + + private void addToQueue(Invoke invoke, RiMethod method) { + invokes.add(invoke); + methods.add(method); + inliningSize += method.code().length; + } + + @Override + protected void run(Graph graph) { + inliningSize = compilation.method.code().length; + int iterations = C1XOptions.MaximumRecursiveInlineLevel; + do { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + RiMethod target = invoke.target; + if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { + continue; + } + if (target.canBeStaticallyBound()) { + if (checkInliningConditions(invoke.target)) { + addToQueue(invoke, invoke.target); + } + } else { + RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); + if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { + if (checkInliningConditions(concrete)) { + if (C1XOptions.TraceInlining) { + System.out.println("registering concrete method assumption..."); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + addToQueue(invoke, concrete); + } + } + } + if (inliningSize > C1XOptions.MaximumInstructionCount) { + break; + } + } + } + + assert invokes.size() == methods.size(); + if (invokes.isEmpty()) { + break; + } + + Invoke invoke; + while ((invoke = invokes.poll()) != null) { + RiMethod method = methods.remove(); + inlineMethod(invoke, method); + } + DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase(); + dce.apply(graph); + if (dce.deletedNodeCount > 0) { + ir.verifyAndPrint("After dead code elimination"); + } + ir.verifyAndPrint("After inlining iteration"); + + if (inliningSize > C1XOptions.MaximumInstructionCount) { + if (C1XOptions.TraceInlining) { + System.out.println("inlining stopped: MaximumInstructionCount reached"); + } + break; + } + } while(--iterations > 0); + } + + private boolean checkInliningConditions(Invoke invoke) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); + if (invoke.predecessors().size() == 0) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because the invoke is dead code"); + } + return false; + } + return true; + } + + private boolean checkInliningConditions(RiMethod method) { + String name = null; + if (C1XOptions.TraceInlining) { + name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + } + if (method.code().length > C1XOptions.MaximumInlineSize) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of code size"); + } + return false; + } + if (!method.holder().isInitialized()) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of non-initialized class"); + } + return false; + } + return true; + } + + private void inlineMethod(Invoke invoke, RiMethod method) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + FrameState stateAfter = invoke.stateAfter(); + Instruction exceptionEdge = invoke.exceptionEdge(); + + if (C1XOptions.TraceInlining) { + System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); + } + + CompilerGraph graph = new CompilerGraph(); + new GraphBuilderPhase(compilation, method, true).apply(graph); + + 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 = graph.start(); + for (Node node : graph.getNodes()) { + if (node != null) { + if (node instanceof StartNode) { + assert 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 (C1XOptions.TraceInlining) { + ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); + System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); + } + + assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); + Instruction pred; + if (withReceiver) { + pred = new NullCheck(parameters[0], compilation.graph); + } else { + pred = new Merge(compilation.graph); + } + 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(); + } + +// if (invoke.next() instanceof Merge) { +// ((Merge) invoke.next()).removePhiPredecessor(invoke); +// } +// invoke.successors().clearAll(); + invoke.inputs().clearAll(); + invoke.setExceptionEdge(null); +// invoke.delete(); + + + if (exceptionEdge != null) { + if (unwindNode != null) { + assert unwindNode.predecessors().size() == 1; + assert exceptionEdge.successors().size() == 1; + ExceptionObject obj = (ExceptionObject) exceptionEdge; + + List usages = new ArrayList(obj.usages()); + for (Node usage : usages) { + if (replacements.containsKey(unwindNode.exception())) { + usage.inputs().replace(obj, replacements.get(unwindNode.exception())); + } else { + usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); + } + } + Node unwindDuplicate = duplicates.get(unwindNode); + unwindDuplicate.inputs().clearAll(); + + assert unwindDuplicate.predecessors().size() == 1; + Node unwindPred = unwindDuplicate.predecessors().get(0); + int index = unwindDuplicate.predecessorsIndex().get(0); + unwindPred.successors().setAndClear(index, obj, 0); + + obj.inputs().clearAll(); + obj.delete(); + unwindDuplicate.delete(); + + } + } + + // adjust all frame states that were copied + if (frameStates.size() > 0) { + FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); + for (Node frameState : frameStates) { + ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); + } + } + + if (C1XOptions.TraceInlining) { + ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); + } + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/SplitCriticalEdgesPhase.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/SplitCriticalEdgesPhase.java Wed Jun 08 13:06:45 2011 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, 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 com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.graph.*; + + +public class SplitCriticalEdgesPhase extends Phase { + + @Override + protected void run(Graph graph) { + List nodes = graph.getNodes(); + for (int i = 0; i < nodes.size(); ++i) { + Node n = nodes.get(i); + if (Schedule.trueSuccessorCount(n) > 1) { + for (int j = 0; j < n.successors().size(); ++j) { + Node succ = n.successors().get(j); + if (Schedule.truePredecessorCount(succ) > 1) { + Anchor a = new Anchor(graph); + a.successors().setAndClear(1, n, j); + n.successors().set(j, a); + } + } + } + } + } +} diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java Wed Jun 08 13:06:45 2011 +0200 @@ -84,6 +84,7 @@ // create node duplicates for (Node node : nodes) { if (node != null && !replacements.containsKey(node)) { + assert node.graph != this; Node newNode = node.copy(this); assert newNode.getClass() == node.getClass(); newNodes.put(node, newNode); diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java Wed Jun 08 13:06:45 2011 +0200 @@ -115,6 +115,18 @@ public boolean isDeleted() { return id == DeletedID; } + + public void forceDelete() { + for (Node n : usages) { + n.inputs.silentRemove(this); + } + for (Node n : predecessors) { + n.successors.silentRemove(this); + } + usages.clear(); + predecessors.clear(); + predecessorsIndex.clear(); + } public void delete() { assert !isDeleted(); diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeArray.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeArray.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeArray.java Wed Jun 08 13:06:45 2011 +0200 @@ -45,14 +45,20 @@ return this.node; } + Node silentSet(int index, Node node) { + Node result = nodes[index]; + nodes[index] = node; + return result; + } + @Override public Node set(int index, Node node) { - assert node == Node.Null || node.graph == self().graph : "node is from different graph: (self=" + self() + ") and (node=" + node + ")"; + assert node == Node.Null || node.graph == self().graph : "node is from different graph: (this=" + self() + ") and (node=" + node + ")"; assert node == Node.Null || node.id() != Node.DeletedID : "inserted node must not be deleted"; Node old = nodes[index]; if (old != node) { - nodes[index] = node; + silentSet(index, node); if (self().inputs == this) { if (old != null) { old.usages.remove(self()); @@ -108,6 +114,10 @@ return false; } + public int remove(Node n) { + return replace(n, null); + } + public int replace(Node toReplace, Node replacement) { int result = 0; for (int i = 0; i < nodes.length; i++) { @@ -118,6 +128,21 @@ } return result; } + + int silentRemove(Node n) { + return silentReplace(n, null); + } + + int silentReplace(Node toReplace, Node replacement) { + int result = 0; + for (int i = 0; i < nodes.length; i++) { + if (nodes[i] == toReplace) { + silentSet(i, replacement); + result++; + } + } + return result; + } public void setAndClear(int index, Node clearedNode, int clearedIndex) { assert self().successors == this; diff -r adfc15cbcabc -r 693e4e92346b graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Phase.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Phase.java Wed Jun 08 13:04:17 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Phase.java Wed Jun 08 13:06:45 2011 +0200 @@ -23,11 +23,25 @@ package com.oracle.max.graal.graph; public abstract class Phase { + + private final String name; + + public Phase() { + this.name = this.getClass().getSimpleName(); + } + + public Phase(String name) { + this.name = name; + } public final void apply(Graph graph) { assert graph != null; run(graph); } + + public final String getName() { + return name; + } protected abstract void run(Graph graph); }