# HG changeset patch # User Gilles Duboscq # Date 1304324656 -7200 # Node ID d524ad648049986b31a500f6db8ad12ce0d9123c # Parent cc1f1d3962883f72b4094e8b052a0b2f94f37946 Finish remove inlining (removed ScopeData), remove JSR support diff -r cc1f1d396288 -r d524ad648049 graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java --- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java Fri Apr 29 16:46:30 2011 +0200 +++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java Mon May 02 10:24:16 2011 +0200 @@ -61,6 +61,25 @@ */ public static final int TRACELEVEL_STATE = 2; + /** + * An enumeration of flags describing scope attributes. + */ + public enum Flag { + /** + * Scope is protected by an exception handler. + * This attribute is inherited by nested scopes. + */ + HasHandler, + + /** + * Code in scope cannot contain safepoints. + * This attribute is inherited by nested scopes. + */ + NoSafepoints; + + public final int mask = 1 << ordinal(); + } + final IR ir; final C1XCompilation compilation; final CiStatistics stats; @@ -75,7 +94,27 @@ */ final MemoryMap memoryMap; - ScopeData scopeData; // Per-scope data; used for inlining + final BytecodeStream stream; // the bytecode stream + // bci-to-block mapping + BlockMap blockMap; + + // the constant pool + final RiConstantPool constantPool; + + // the worklist of blocks, managed like a sorted list + BlockBegin[] workList; + + // the current position in the worklist + int workListIndex; + + /** + * Mask of {@link Flag} values. + */ + int flags; + + // Exception handler list + List exceptionHandlers; + BlockBegin curBlock; // the current block MutableFrameState curState; // the current execution state Instruction lastInstr; // the last instruction added @@ -83,7 +122,6 @@ boolean skipBlock; // skip processing of the rest of this block private Value rootMethodSynchronizedObject; - /** * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. * @@ -97,6 +135,8 @@ this.memoryMap = C1XOptions.OptLocalLoadElimination ? new MemoryMap() : null; this.localValueMap = C1XOptions.OptLocalValueNumbering ? new ValueMap() : null; log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; + stream = new BytecodeStream(compilation.method.code()); + constantPool = compilation.runtime.getConstantPool(compilation.method); } /** @@ -111,14 +151,30 @@ log.println("Compiling " + compilation.method); } + if (rootMethod.noSafepoints()) { + flags |= Flag.NoSafepoints.mask; + } + // 1. create the start block ir.startBlock = new BlockBegin(0, ir.nextBlockNumber()); BlockBegin startBlock = ir.startBlock; - // 2. compute the block map and get the entrypoint(s) - BlockMap blockMap = compilation.getBlockMap(rootMethod); + // 2. compute the block map, setup exception handlers and get the entrypoint(s) + blockMap = compilation.getBlockMap(rootMethod); BlockBegin stdEntry = blockMap.get(0); - pushRootScope(rootMethod, blockMap, startBlock); + curBlock = startBlock; + + RiExceptionHandler[] handlers = rootMethod.exceptionHandlers(); + if (handlers != null && handlers.length > 0) { + exceptionHandlers = new ArrayList(handlers.length); + for (RiExceptionHandler ch : handlers) { + ExceptionHandler h = new ExceptionHandler(ch); + h.setEntryBlock(blockAt(h.handler.handlerBCI())); + exceptionHandlers.add(h); + } + flags |= Flag.HasHandler.mask; + } + MutableFrameState initialState = stateAtEntry(rootMethod); startBlock.mergeOrClone(initialState, rootMethod); BlockBegin syncHandler = null; @@ -144,7 +200,7 @@ ExceptionHandler h = new ExceptionHandler(new CiExceptionHandler(0, rootMethod.code().length, -1, 0, null)); h.setEntryBlock(syncHandler); - scopeData.addExceptionHandler(h); + addExceptionHandler(h); } else { // 4B.1 simply finish the start block finishStartBlock(startBlock, stdEntry); @@ -153,7 +209,7 @@ // 5. SKIPPED: look for intrinsics // 6B.1 do the normal parsing - scopeData.addToWorkList(stdEntry); + addToWorkList(stdEntry); iterateAllBlocks(); if (syncHandler != null && syncHandler.stateBefore() != null) { @@ -173,31 +229,20 @@ stdEntry.mergeOrClone(stateAfter, method()); } - void pushRootScope(RiMethod method, BlockMap blockMap, BlockBegin start) { - BytecodeStream stream = new BytecodeStream(method.code()); - RiConstantPool constantPool = compilation.runtime.getConstantPool(method); - scopeData = new ScopeData(null, method, blockMap, stream, constantPool); - curBlock = start; - } - - public boolean hasHandler() { - return scopeData.hasHandler(); - } - public RiMethod method() { return compilation.method; } public BytecodeStream stream() { - return scopeData.stream; + return stream; } public int bci() { - return scopeData.stream.currentBCI(); + return stream.currentBCI(); } public int nextBCI() { - return scopeData.stream.nextBCI(); + return stream.nextBCI(); } private void ipush(Value x) { @@ -277,73 +322,28 @@ } private void storeLocal(CiKind kind, int index) { - if (scopeData.parsingJsr()) { - // We need to do additional tracking of the location of the return - // address for jsrs since we don't handle arbitrary jsr/ret - // constructs. Here we are figuring out in which circumstances we - // need to bail out. - if (kind == CiKind.Object) { - // might be storing the JSR return address - Value x = curState.xpop(); - if (x.kind.isJsr()) { - setJsrReturnAddressLocal(index); - curState.storeLocal(index, x); - } else { - // nope, not storing the JSR return address - assert x.kind.isObject(); - curState.storeLocal(index, x); - overwriteJsrReturnAddressLocal(index); - } - return; - } else { - // not storing the JSR return address local, but might overwrite it - overwriteJsrReturnAddressLocal(index); - } - } - curState.storeLocal(index, pop(kind)); } - private void overwriteJsrReturnAddressLocal(int index) { - if (index == scopeData.jsrEntryReturnAddressLocal()) { - scopeData.setJsrEntryReturnAddressLocal(-1); - } - } - - private void setJsrReturnAddressLocal(int index) { - scopeData.setJsrEntryReturnAddressLocal(index); - - // Also check parent jsrs (if any) at this time to see whether - // they are using this local. We don't handle skipping over a - // ret. - for (ScopeData cur = scopeData.parent; cur != null && cur.parsingJsr(); cur = cur.parent) { - if (cur.jsrEntryReturnAddressLocal() == index) { - throw new CiBailout("subroutine overwrites return address from previous subroutine"); - } - } - } - List handleException(Instruction x, int bci) { if (!hasHandler()) { return Util.uncheckedCast(Collections.EMPTY_LIST); } ArrayList exceptionHandlers = new ArrayList(); - ScopeData curScopeData = scopeData; FrameState stateBefore = x.stateBefore(); int scopeCount = 0; assert stateBefore != null : "exception handler state must be available for " + x; FrameState state = stateBefore; - assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == curScopeData.stream.currentBCI() : "invalid bci"; + assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; // join with all potential exception handlers - List handlers = curScopeData.exceptionHandlers(); - if (handlers != null) { - for (ExceptionHandler handler : handlers) { + if (this.exceptionHandlers != null) { + for (ExceptionHandler handler : this.exceptionHandlers) { if (handler.covers(bci)) { // if the handler covers this bytecode index, add it to the list - if (addExceptionHandler(exceptionHandlers, handler, curScopeData, state, scopeCount)) { + if (addExceptionHandler(exceptionHandlers, handler, state, scopeCount)) { // if the handler was a default handler, we are done return exceptionHandlers; } @@ -365,15 +365,14 @@ * @param scopeCount * @return {@code true} if handler catches all exceptions (i.e. {@code handler.isCatchAll() == true}) */ - private boolean addExceptionHandler(ArrayList exceptionHandlers, ExceptionHandler handler, ScopeData curScopeData, FrameState curState, int scopeCount) { + private boolean addExceptionHandler(ArrayList exceptionHandlers, ExceptionHandler handler, FrameState curState, int scopeCount) { compilation.setHasExceptionHandlers(); BlockBegin entry = handler.entryBlock(); FrameState entryState = entry.stateBefore(); assert entry.bci() == handler.handler.handlerBCI(); - assert entry.bci() == -1 || entry == curScopeData.blockAt(entry.bci()) : "blocks must correspond"; - assert entryState == null || curState.locksSize() == entryState.locksSize() : "locks do not match"; + assert entryState == null || curState.locksSize() == entryState.locksSize() : "locks do not match : cur:"+curState.locksSize()+" entry:"+entryState.locksSize(); // exception handler starts with an empty expression stack curState = curState.immutableCopyWithEmptyStack(); @@ -399,7 +398,7 @@ // fill in exception handler subgraph lazily if (!entry.wasVisited()) { - curScopeData.addToWorkList(entry); + addToWorkList(entry); } else { // This will occur for exception handlers that cover themselves. This code // pattern is generated by javac for synchronized blocks. See the following @@ -595,7 +594,7 @@ } void genGoto(int fromBCI, int toBCI) { - boolean isSafepoint = !scopeData.noSafepoints() && toBCI <= fromBCI; + boolean isSafepoint = !noSafepoints() && toBCI <= fromBCI; append(new Goto(blockAt(toBCI), null, isSafepoint)); } @@ -603,7 +602,7 @@ BlockBegin tsucc = blockAt(stream().readBranchDest()); BlockBegin fsucc = blockAt(stream().nextBCI()); int bci = stream().currentBCI(); - boolean isSafepoint = !scopeData.noSafepoints() && tsucc.bci() <= bci || fsucc.bci() <= bci; + boolean isSafepoint = !noSafepoints() && tsucc.bci() <= bci || fsucc.bci() <= bci; append(new If(x, cond, y, tsucc, fsucc, isSafepoint ? stateBefore : null, isSafepoint)); } @@ -630,7 +629,7 @@ void genThrow(int bci) { FrameState stateBefore = curState.immutableCopy(bci()); - Throw t = new Throw(apop(), stateBefore, !scopeData.noSafepoints()); + Throw t = new Throw(apop(), stateBefore, !noSafepoints()); appendWithoutOptimization(t, bci); } @@ -1007,44 +1006,6 @@ callRegisterFinalizer(); } - // If inlining, then returns become gotos to the continuation point. - if (scopeData.continuation() != null) { - if (isSynchronized(method().accessFlags())) { - // if the inlined method is synchronized, then the monitor - // must be released before jumping to the continuation point - Value object = curState.lockAt(0); - if (object instanceof Instruction) { - Instruction obj = (Instruction) object; - if (!obj.isAppended()) { - appendWithoutOptimization(obj, Instruction.SYNCHRONIZATION_ENTRY_BCI); - } - } - genMonitorExit(object, Instruction.SYNCHRONIZATION_ENTRY_BCI); - } - - // empty stack for return value - curState.truncateStack(0); - if (x != null) { - curState.push(x.kind, x); - } - Goto gotoCallee = new Goto(scopeData.continuation(), null, false); - - // ATTN: assumption: curState is not used further down, else add .immutableCopy() - scopeData.updateSimpleInlineInfo(curBlock, lastInstr, curState); - - // State at end of inlined method is the state of the caller - // without the method parameters on stack, including the - // return value, if any, of the inlined method on operand stack. - curState = scopeData.continuationState().copy(); - if (x != null) { - curState.push(x.kind, x); - } - - // The current bci is in the wrong scope, so use the bci of the continuation point. - appendWithoutOptimization(gotoCallee, scopeData.continuation().bci()); - return; - } - curState.truncateStack(0); if (Modifier.isSynchronized(method().accessFlags())) { FrameState stateBefore = curState.immutableCopy(bci()); @@ -1058,7 +1019,7 @@ append(new MonitorExit(rootMethodSynchronizedObject, lockAddress, lockNumber, stateBefore)); curState.unlock(); } - append(new Return(x, !scopeData.noSafepoints())); + append(new Return(x, !noSafepoints())); } /** @@ -1098,27 +1059,11 @@ } void genJsr(int dest) { - for (ScopeData cur = scopeData; cur != null && cur.parsingJsr(); cur = cur.parent) { - if (cur.jsrEntryBCI() == dest) { - // the jsr/ret pattern includes a recursive invocation - throw new CiBailout("recursive jsr/ret structure"); - } - } - System.err.println("> JSR!"); - push(CiKind.Jsr, append(Constant.forJsr(nextBCI()))); - tryInlineJsr(dest); + throw new CiBailout("jsr/ret not supported"); } void genRet(int localIndex) { - if (!scopeData.parsingJsr()) { - throw new CiBailout("ret encountered when not parsing subroutine"); - } - - if (localIndex != scopeData.jsrEntryReturnAddressLocal()) { - throw new CiBailout("jsr/ret structure is too complicated"); - } - // rets become non-safepoint gotos - append(new Goto(scopeData.jsrContinuation(), null, false)); + throw new CiBailout("jsr/ret not supported"); } void genTableswitch() { @@ -1136,7 +1081,7 @@ int offset = ts.defaultOffset(); isBackwards |= offset < 0; // if the default successor is backwards list.add(blockAt(bci + offset)); - boolean isSafepoint = isBackwards && !scopeData.noSafepoints(); + boolean isSafepoint = isBackwards && !noSafepoints(); FrameState stateBefore = isSafepoint ? curState.immutableCopy(bci()) : null; append(new TableSwitch(ipop(), list, ts.lowKey(), stateBefore, isSafepoint)); } @@ -1158,7 +1103,7 @@ int offset = ls.defaultOffset(); isBackwards |= offset < 0; // if the default successor is backwards list.add(blockAt(bci + offset)); - boolean isSafepoint = isBackwards && !scopeData.noSafepoints(); + boolean isSafepoint = isBackwards && !noSafepoints(); FrameState stateBefore = isSafepoint ? curState.immutableCopy(bci()) : null; append(new LookupSwitch(ipop(), list, keys, stateBefore, isSafepoint)); } @@ -1254,7 +1199,7 @@ } private BlockBegin blockAtOrNull(int bci) { - return scopeData.blockAt(bci); + return blockMap.get(bci); } private BlockBegin blockAt(int bci) { @@ -1263,59 +1208,6 @@ return result; } - boolean tryInlineJsr(int jsrStart) { - // start a new continuation point. - // all ret instructions will be replaced with gotos to this point - BlockBegin cont = blockAt(nextBCI()); - - // push callee scope - pushScopeForJsr(cont, jsrStart); - - BlockBegin jsrStartBlock = blockAt(jsrStart); - assert !jsrStartBlock.wasVisited(); - Goto gotoSub = new Goto(jsrStartBlock, null, false); - gotoSub.setStateAfter(curState.immutableCopy(bci())); - assert jsrStartBlock.stateBefore() == null; - jsrStartBlock.setStateBefore(curState.immutableCopy(bci())); - append(gotoSub); - curBlock.setEnd(gotoSub); - lastInstr = curBlock = jsrStartBlock; - - scopeData.addToWorkList(jsrStartBlock); - - iterateAllBlocks(); - - if (cont.stateBefore() != null) { - if (!cont.wasVisited()) { - scopeData.parent.addToWorkList(cont); - } - } - - BlockBegin jsrCont = scopeData.jsrContinuation(); - assert jsrCont == cont && (!jsrCont.wasVisited() || jsrCont.isParserLoopHeader()); - assert lastInstr != null && lastInstr instanceof BlockEnd; - - // continuation is in work list, so end iteration of current block - skipBlock = true; - popScopeForJsr(); - C1XMetrics.InlinedJsrs++; - return true; - } - - void pushScopeForJsr(BlockBegin jsrCont, int jsrStart) { - BytecodeStream stream = new BytecodeStream(compilation.method.code()); - RiConstantPool constantPool = scopeData.constantPool; - ScopeData data = new ScopeData(scopeData, compilation.method, scopeData.blockMap, stream, constantPool, jsrStart); - BlockBegin continuation = scopeData.continuation(); - data.setContinuation(continuation); - if (continuation != null) { - assert scopeData.continuationState() != null; - data.setContinuationState(scopeData.continuationState().copy()); - } - data.setJsrContinuation(jsrCont); - scopeData = data; - } - MutableFrameState stateAtEntry(RiMethod method) { MutableFrameState state = new MutableFrameState(-1, method.maxLocals(), method.maxStackSize()); int index = 0; @@ -1391,7 +1283,7 @@ private void iterateAllBlocks() { BlockBegin b; - while ((b = scopeData.removeFromWorkList()) != null) { + while ((b = removeFromWorkList()) != null) { if (!b.wasVisited()) { b.setWasVisited(true); // now parse the block @@ -1406,21 +1298,16 @@ } } - private void popScopeForJsr() { - scopeData = scopeData.parent; - } - private BlockEnd iterateBytecodesForBlock(int bci, boolean inliningIntoCurrentBlock) { skipBlock = false; assert curState != null; - BytecodeStream s = scopeData.stream; - s.setBCI(bci); + stream.setBCI(bci); BlockBegin block = curBlock; BlockEnd end = null; boolean pushException = block.isExceptionEntry() && block.next() == null; int prevBCI = bci; - int endBCI = s.endBCI(); + int endBCI = stream.endBCI(); boolean blockStart = true; while (bci < endBCI) { @@ -1440,7 +1327,7 @@ break; } // read the opcode - int opcode = s.currentBC(); + int opcode = stream.currentBC(); // push an exception object onto the stack if we are parsing an exception handler if (pushException) { @@ -1450,8 +1337,8 @@ } traceState(); - traceInstruction(bci, s, opcode, blockStart); - processBytecode(bci, s, opcode); + traceInstruction(bci, stream, opcode, blockStart); + processBytecode(bci, stream, opcode); prevBCI = bci; @@ -1459,8 +1346,8 @@ end = (BlockEnd) lastInstr; break; } - s.next(); - bci = s.currentBCI(); + stream.next(); + bci = stream.currentBCI(); blockStart = false; } @@ -1484,7 +1371,7 @@ for (BlockBegin succ : end.successors()) { assert succ.predecessors().contains(curBlock); succ.mergeOrClone(end.stateAfter(), method()); - scopeData.addToWorkList(succ); + addToWorkList(succ); } return end; } @@ -1796,6 +1683,88 @@ } private RiConstantPool constantPool() { - return scopeData.constantPool; + return constantPool; + } + + /** + * Adds an exception handler + * @param handler the handler to add + */ + private void addExceptionHandler(ExceptionHandler handler) { + if (exceptionHandlers == null) { + exceptionHandlers = new ArrayList(); + } + exceptionHandlers.add(handler); + flags |= Flag.HasHandler.mask; + } + + /** + * 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(BlockBegin block) { + if (!block.isOnWorkList()) { + block.setOnWorkList(true); + sortIntoWorkList(block); + } + } + + private void sortIntoWorkList(BlockBegin top) { + // XXX: this is O(n), since the whole list is sorted; a heap could achieve O(nlogn), but + // would only pay off for large worklists + if (workList == null) { + // need to allocate the worklist + workList = new BlockBegin[5]; + } else if (workListIndex == workList.length) { + // need to grow the worklist + BlockBegin[] nworkList = new BlockBegin[workList.length * 3]; + System.arraycopy(workList, 0, nworkList, 0, workList.length); + workList = nworkList; + } + // put the block at the end of the array + workList[workListIndex++] = top; + int dfn = top.depthFirstNumber(); + assert dfn >= 0 : top + " does not have a depth first number"; + int i = workListIndex - 2; + // push top towards the beginning of the array + for (; i >= 0; i--) { + BlockBegin b = workList[i]; + if (b.depthFirstNumber() >= dfn) { + break; // already in the right position + } + workList[i + 1] = b; // bubble b down by one + workList[i] = top; // and overwrite it with 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 BlockBegin removeFromWorkList() { + if (workListIndex == 0) { + return null; + } + // pop the last item off the end + return workList[--workListIndex]; + } + + /** + * Checks whether this graph has any handlers. + * @return {@code true} if there are any exception handlers + */ + private boolean hasHandler() { + return (flags & Flag.HasHandler.mask) != 0; + } + + /** + * Checks whether this graph can contain safepoints. + */ + private boolean noSafepoints() { + return (flags & Flag.NoSafepoints.mask) != 0; } } diff -r cc1f1d396288 -r d524ad648049 graal/GraalCompiler/src/com/sun/c1x/graph/ScopeData.java --- a/graal/GraalCompiler/src/com/sun/c1x/graph/ScopeData.java Fri Apr 29 16:46:30 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,502 +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.sun.c1x.graph; - -import static com.sun.c1x.graph.ScopeData.Flag.*; -import static com.sun.c1x.graph.ScopeData.ReturnBlock.*; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.value.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ri.*; - -/** - * The {@code ScopeData} class represents inlining context when parsing the bytecodes - * of an inlined method. - * - * @author Ben L. Titzer -*/ -public class ScopeData { - // XXX: refactor and split this class into ScopeData, JsrScopeData, and InlineScopeData - - /** - * An enumeration of flags describing scope attributes. - */ - public enum Flag { - /** - * Scope is protected by an exception handler. - * This attribute is inherited by nested scopes. - */ - HasHandler, - - /** - * Code in scope cannot contain safepoints. - * This attribute is inherited by nested scopes. - */ - NoSafepoints; - - public final int mask = 1 << ordinal(); - } - - - final ScopeData parent; - // - final RiMethod method; - // bci-to-block mapping - final BlockMap blockMap; - // the bytecode stream - final BytecodeStream stream; - // the constant pool - final RiConstantPool constantPool; - // the worklist of blocks, managed like a sorted list - BlockBegin[] workList; - // the current position in the worklist - int workListIndex; - // maximum inline size for this scope - int maxInlineSize; - - /** - * Mask of {@link Flag} values. - */ - int flags; - - // Exception handler list - List exceptionHandlers; - - // The continuation point for the inline. Currently only used in - // multi-block inlines, but eventually would like to use this for - // all inlines for uniformity and simplicity; in this case would - // get the continuation point from the BlockList instead of - // fabricating it anew because Invokes would be considered to be - // BlockEnds. - BlockBegin continuation; - - // Without return value of inlined method on stack - FrameState continuationState; - - /** - * Field used to generate fewer blocks when inlining. If this value is {@code null}, - * then no {@code return}s have been encountered during inlining. If it is an instance - * of {@link ReturnBlock}, then it is the block info for the single {@code return} - * encountered. Otherwise, it will be {@link ReturnBlock#MULTIPLE_RETURNS}. - */ - ReturnBlock inlinedReturnBlock; - - /** - * Tracks the destination bci of the jsr. This is (currently) only used to determine - * bailout conditions, since only a subset of all of the possible jsr-ret control - * structures can (currently) be compiled. - * - * A value > 0 for this field indicates parsing of a jsr. - */ - final int jsrEntryBci; - - // We need to track the local variable in which the return address - // was stored to ensure we can handle inlining the jsr, because we - // don't handle arbitrary jsr/ret constructs. - int jsrRetAddrLocal; - - // If we are parsing a jsr, the continuation point for rets - BlockBegin jsrContinuation; - - final BlockBegin[] jsrDuplicatedBlocks; // blocks that have been duplicated for JSR inlining - - /** - * Constructs a new ScopeData instance with the specified parent ScopeData. - * @param parent the parent scope data - * @param scope the IR scope - * @param blockMap the block map for this scope - * @param stream the bytecode stream - * @param constantPool the constant pool - */ - public ScopeData(ScopeData parent, RiMethod method, BlockMap blockMap, BytecodeStream stream, RiConstantPool constantPool) { - this.parent = parent; - this.method = method; - this.blockMap = blockMap; - this.stream = stream; - this.constantPool = constantPool; - this.jsrEntryBci = -1; - this.jsrDuplicatedBlocks = null; - if (parent != null) { - maxInlineSize = (int) (C1XOptions.MaximumInlineRatio * parent.maxInlineSize()); - if (maxInlineSize < C1XOptions.MaximumTrivialSize) { - maxInlineSize = C1XOptions.MaximumTrivialSize; - } - if (parent.hasHandler()) { - flags |= HasHandler.mask; - } - if (parent.noSafepoints() || method.noSafepoints()) { - flags |= NoSafepoints.mask; - } - } else { - maxInlineSize = C1XOptions.MaximumInlineSize; - if (method.noSafepoints()) { - flags |= NoSafepoints.mask; - } - } - RiExceptionHandler[] handlers = method.exceptionHandlers(); - if (handlers != null && handlers.length > 0) { - exceptionHandlers = new ArrayList(handlers.length); - for (RiExceptionHandler ch : handlers) { - ExceptionHandler h = new ExceptionHandler(ch); - h.setEntryBlock(blockAt(h.handler.handlerBCI())); - exceptionHandlers.add(h); - } - flags |= HasHandler.mask; - } - } - - /** - * Constructs a new ScopeData instance with the specified parent ScopeData. This constructor variant creates - * a scope data for parsing a JSR. - * @param parent the parent scope data - * @param scope the IR scope - * @param blockMap the block map for this scope - * @param stream the bytecode stream - * @param constantPool the constant pool - * @param jsrEntryBci the bytecode index of the entrypoint of the JSR - */ - public ScopeData(ScopeData parent, RiMethod method, BlockMap blockMap, BytecodeStream stream, RiConstantPool constantPool, int jsrEntryBci) { - this.parent = parent; - this.method = method; - this.blockMap = blockMap; - this.stream = stream; - this.constantPool = constantPool; - assert jsrEntryBci > 0 : "jsr cannot jump to BCI 0"; - assert parent != null : "jsr must have parent scope"; - this.jsrEntryBci = jsrEntryBci; - this.jsrDuplicatedBlocks = new BlockBegin[method.code().length]; - this.jsrRetAddrLocal = -1; - - maxInlineSize = (int) (C1XOptions.MaximumInlineRatio * parent.maxInlineSize()); - if (maxInlineSize < C1XOptions.MaximumTrivialSize) { - maxInlineSize = C1XOptions.MaximumTrivialSize; - } - flags = parent.flags; - - // duplicate the parent scope's exception handlers, if any - List handlers = parent.exceptionHandlers(); - if (handlers != null && handlers.size() > 0) { - exceptionHandlers = new ArrayList(handlers.size()); - for (ExceptionHandler ph : handlers) { - ExceptionHandler h = new ExceptionHandler(ph); - int handlerBci = h.handler.handlerBCI(); - if (handlerBci >= 0) { - // need to duplicate the handler block because it is a "normal" handler - h.setEntryBlock(blockAt(handlerBci)); - } else { - // don't duplicate the handler block because it is a synchronization handler - // that was added by parsing/inlining a synchronized method - assert ph.entryBlock().checkBlockFlag(BlockBegin.BlockFlag.DefaultExceptionHandler); - h.setEntryBlock(ph.entryBlock()); - } - exceptionHandlers.add(h); - } - assert hasHandler(); - } - } - - /** - * Gets the block beginning at the specified bytecode index. Note that this method - * will clone the block if it the scope data is currently parsing a JSR. - * @param bci the bytecode index of the start of the block - * @return the block starting at the specified bytecode index - */ - public BlockBegin blockAt(int bci) { - if (jsrDuplicatedBlocks != null) { - // all blocks in a JSR are duplicated on demand using an internal array, - // including those for exception handlers in the scope of the method - // containing the jsr (because those exception handlers may contain ret - // instructions in some cases). - BlockBegin block = jsrDuplicatedBlocks[bci]; - if (block == null) { - BlockBegin p = this.parent.blockAt(bci); - if (p != null) { - BlockBegin newBlock = new BlockBegin(p.bci(), C1XCompilation.compilation().hir().nextBlockNumber()); - newBlock.setDepthFirstNumber(p.depthFirstNumber()); - newBlock.copyBlockFlags(p); - jsrDuplicatedBlocks[bci] = newBlock; - block = newBlock; - } - } - return block; - } - return blockMap.get(bci); - } - - /** - * Checks whether this scope has any handlers. - * @return {@code true} if there are any exception handlers - */ - public boolean hasHandler() { - return (flags & Flag.HasHandler.mask) != 0; - } - - /** - * Checks whether this scope can contain safepoints. - */ - public boolean noSafepoints() { - return (flags & Flag.NoSafepoints.mask) != 0; - } - - /** - * Gets the maximum inline size. - * @return the maximum inline size - */ - public int maxInlineSize() { - return maxInlineSize; - } - - /** - * Gets the block continuation for this ScopeData. - * @return the continuation - */ - public BlockBegin continuation() { - return continuation; - } - - /** - * Sets the continuation for this ScopeData. - * @param continuation the continuation - */ - public void setContinuation(BlockBegin continuation) { - this.continuation = continuation; - } - - /** - * Gets the state at the continuation point. - * @return the state at the continuation point - */ - public FrameState continuationState() { - return continuationState; - } - - /** - * Sets the state at the continuation point. - * @param state the state at the continuation - */ - public void setContinuationState(FrameState state) { - continuationState = state; - } - - /** - * Checks whether this ScopeData is parsing a JSR. - * @return {@code true} if this scope data is parsing a JSR - */ - public boolean parsingJsr() { - return jsrEntryBci > 0; - } - - /** - * Gets the bytecode index for the JSR entry. - * @return the jsr entry bci - */ - public int jsrEntryBCI() { - return jsrEntryBci; - } - - /** - * Gets the index of the local variable containing the JSR return address. - * @return the index of the local with the JSR return address - */ - public int jsrEntryReturnAddressLocal() { - return jsrRetAddrLocal; - } - - /** - * Sets the index of the local variable containing the JSR return address. - * @param local the local - */ - public void setJsrEntryReturnAddressLocal(int local) { - jsrRetAddrLocal = local; - } - - /** - * Gets the continuation for parsing a JSR. - * @return the jsr continuation - */ - public BlockBegin jsrContinuation() { - return jsrContinuation; - } - - /** - * Sets the continuation for parsing a JSR. - * @param block the block that is the continuation - */ - public void setJsrContinuation(BlockBegin block) { - jsrContinuation = block; - } - - /** - * A block delimited by a return instruction in an inlined method. - */ - public static class ReturnBlock { - /** - * The inlined block. - */ - final BlockBegin block; - - /** - * The second last instruction in the block. That is, the one before the return instruction. - */ - final Instruction returnPredecessor; - - /** - * The frame state at the end of the block. - */ - final FrameState returnState; - - ReturnBlock(BlockBegin block, Instruction returnPredecessor, FrameState returnState) { - super(); - this.block = block; - this.returnPredecessor = returnPredecessor; - this.returnState = returnState; - } - - public static final ReturnBlock MULTIPLE_RETURNS = new ReturnBlock(null, null, null); - } - - /** - * Updates the info about blocks in this scope delimited by a return instruction. - * - * @param block a block delimited by a {@code return} instruction - * @param returnPredecessor the second last instruction in the block. That is, the one before the return instruction. - * @param returnState the frame state after the return instruction - */ - public void updateSimpleInlineInfo(BlockBegin block, Instruction returnPredecessor, FrameState returnState) { - if (inlinedReturnBlock == null) { - inlinedReturnBlock = new ReturnBlock(block, returnPredecessor, returnState); - } else { - inlinedReturnBlock = MULTIPLE_RETURNS; - } - } - - /** - * Gets the return block info for a simple inline scope. That is, a scope that contains only a - * single block delimited by a {@code return} instruction. - * - * @return the return block info for a simple inline scope or {@code null} if this is not a simple inline scope - */ - public ReturnBlock simpleInlineInfo() { - if (inlinedReturnBlock == MULTIPLE_RETURNS) { - return null; - } - return inlinedReturnBlock; - } - - /** - * Gets the list of exception handlers for this scope data. - * @return the list of exception handlers - */ - public List exceptionHandlers() { - return exceptionHandlers; - } - - /** - * Adds an exception handler to this scope data. - * @param handler the handler to add - */ - public void addExceptionHandler(ExceptionHandler handler) { - if (exceptionHandlers == null) { - exceptionHandlers = new ArrayList(); - } - assert !parsingJsr() : "jsr scope should already have all the handlers it needs"; - exceptionHandlers.add(handler); - flags |= HasHandler.mask; - } - - /** - * 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 - */ - public void addToWorkList(BlockBegin block) { - if (!block.isOnWorkList()) { - if (block == continuation || block == jsrContinuation) { - return; - } - block.setOnWorkList(true); - sortIntoWorkList(block); - } - } - - private void sortIntoWorkList(BlockBegin top) { - // XXX: this is O(n), since the whole list is sorted; a heap could achieve O(nlogn), but - // would only pay off for large worklists - if (workList == null) { - // need to allocate the worklist - workList = new BlockBegin[5]; - } else if (workListIndex == workList.length) { - // need to grow the worklist - BlockBegin[] nworkList = new BlockBegin[workList.length * 3]; - System.arraycopy(workList, 0, nworkList, 0, workList.length); - workList = nworkList; - } - // put the block at the end of the array - workList[workListIndex++] = top; - int dfn = top.depthFirstNumber(); - assert dfn >= 0 : top + " does not have a depth first number"; - int i = workListIndex - 2; - // push top towards the beginning of the array - for (; i >= 0; i--) { - BlockBegin b = workList[i]; - if (b.depthFirstNumber() >= dfn) { - break; // already in the right position - } - workList[i + 1] = b; // bubble b down by one - workList[i] = top; // and overwrite it with 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 - */ - public BlockBegin removeFromWorkList() { - if (workListIndex == 0) { - return null; - } - // pop the last item off the end - return workList[--workListIndex]; - } - - /** - * Converts this scope data to a string for debugging purposes. - * @return a string representation of this scope data - */ - @Override - public String toString() { - if (parsingJsr()) { - return "jsr@" + jsrEntryBci + " data for " + method.toString(); - } else { - return "data for " + method.toString(); - } - - } -} diff -r cc1f1d396288 -r d524ad648049 rundacapo.sh --- a/rundacapo.sh Fri Apr 29 16:46:30 2011 +0200 +++ b/rundacapo.sh Mon May 02 10:24:16 2011 +0200 @@ -15,4 +15,4 @@ echo "DACAPO is not defined. It must point to a SciMark benchmark directory." exit 1; fi -${JDK7}/bin/java -client -graal -Xms1g -Xmx2g -esa -classpath ${DACAPO}/dacapo-9.12-bach.jar Harness $* +${JDK7}/bin/java -client -graal -XX:-C1XBailoutIsFatal -Xms1g -Xmx2g -esa -classpath ${DACAPO}/dacapo-9.12-bach.jar Harness $*