changeset 2566:d524ad648049

Finish remove inlining (removed ScopeData), remove JSR support
author Gilles Duboscq <gilles.duboscq@oracle.com>
date Mon, 02 May 2011 10:24:16 +0200
parents cc1f1d396288
children b96f9fcc53b1
files graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java graal/GraalCompiler/src/com/sun/c1x/graph/ScopeData.java rundacapo.sh
diffstat 3 files changed, 175 insertions(+), 708 deletions(-) [+]
line wrap: on
line diff
--- 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<ExceptionHandler> 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<ExceptionHandler>(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<ExceptionHandler> handleException(Instruction x, int bci) {
         if (!hasHandler()) {
             return Util.uncheckedCast(Collections.EMPTY_LIST);
         }
 
         ArrayList<ExceptionHandler> exceptionHandlers = new ArrayList<ExceptionHandler>();
-        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<ExceptionHandler> 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<ExceptionHandler> exceptionHandlers, ExceptionHandler handler, ScopeData curScopeData, FrameState curState, int scopeCount) {
+    private boolean addExceptionHandler(ArrayList<ExceptionHandler> 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<ExceptionHandler>();
+        }
+        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;
     }
 }
--- 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<ExceptionHandler> 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<ExceptionHandler>(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<ExceptionHandler> handlers = parent.exceptionHandlers();
-        if (handlers != null && handlers.size() > 0) {
-            exceptionHandlers = new ArrayList<ExceptionHandler>(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<ExceptionHandler> 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<ExceptionHandler>();
-        }
-        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();
-        }
-
-    }
-}
--- 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 $*