--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java 2016-12-09 00:50:10.817142492 -0800 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2009, 2015, 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 org.graalvm.compiler.java; + +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.IINC; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2; +import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3; +import static org.graalvm.compiler.bytecode.Bytecodes.RET; + +import org.graalvm.compiler.bytecode.BytecodeStream; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.java.BciBlockMapping.BciBlock; + +/** + * Encapsulates the liveness calculation, so that subclasses for locals ≤ 64 and locals > 64 + * can be implemented. + */ +public abstract class LocalLiveness { + protected final BciBlock[] blocks; + + public static LocalLiveness compute(BytecodeStream stream, BciBlock[] blocks, int maxLocals, int loopCount) { + LocalLiveness liveness = maxLocals <= 64 ? new SmallLocalLiveness(blocks, maxLocals, loopCount) : new LargeLocalLiveness(blocks, maxLocals, loopCount); + liveness.computeLiveness(stream); + return liveness; + } + + protected LocalLiveness(BciBlock[] blocks) { + this.blocks = blocks; + } + + void computeLiveness(BytecodeStream stream) { + for (BciBlock block : blocks) { + computeLocalLiveness(stream, block); + } + + boolean changed; + int iteration = 0; + do { + assert traceIteration(iteration); + changed = false; + for (int i = blocks.length - 1; i >= 0; i--) { + BciBlock block = blocks[i]; + int blockID = block.getId(); + assert traceStart(block, blockID); + + boolean blockChanged = (iteration == 0); + if (block.getSuccessorCount() > 0) { + int oldCardinality = liveOutCardinality(blockID); + for (BciBlock sux : block.getSuccessors()) { + assert traceSuccessor(sux); + propagateLiveness(blockID, sux.getId()); + } + blockChanged |= (oldCardinality != liveOutCardinality(blockID)); + } + + if (blockChanged) { + updateLiveness(blockID); + assert traceEnd(block, blockID); + } + changed |= blockChanged; + } + iteration++; + } while (changed); + } + + private static boolean traceIteration(int iteration) { + Debug.log("Iteration %d", iteration); + return true; + } + + private boolean traceEnd(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + + private boolean traceSuccessor(BciBlock sux) { + if (Debug.isLogEnabled()) { + Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); + } + return true; + } + + private boolean traceStart(BciBlock block, int blockID) { + if (Debug.isLogEnabled()) { + Debug.logv(" start B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID), debugLiveGen(blockID), + debugLiveKill(blockID)); + } + return true; + } + + /** + * Returns whether the local is live at the beginning of the given block. + */ + public abstract boolean localIsLiveIn(BciBlock block, int local); + + /** + * Returns whether the local is set in the given loop. + */ + public abstract boolean localIsChangedInLoop(int loopId, int local); + + /** + * Returns whether the local is live at the end of the given block. + */ + public abstract boolean localIsLiveOut(BciBlock block, int local); + + /** + * Returns a string representation of the liveIn values of the given block. + */ + protected abstract String debugLiveIn(int blockID); + + /** + * Returns a string representation of the liveOut values of the given block. + */ + protected abstract String debugLiveOut(int blockID); + + /** + * Returns a string representation of the liveGen values of the given block. + */ + protected abstract String debugLiveGen(int blockID); + + /** + * Returns a string representation of the liveKill values of the given block. + */ + protected abstract String debugLiveKill(int blockID); + + /** + * Returns the number of live locals at the end of the given block. + */ + protected abstract int liveOutCardinality(int blockID); + + /** + * Adds all locals the are in the liveIn of the successor to the liveOut of the block. + */ + protected abstract void propagateLiveness(int blockID, int successorID); + + /** + * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen. + */ + protected abstract void updateLiveness(int blockID); + + /** + * Adds the local to liveGen if it wasn't already killed in this block. + */ + protected abstract void loadOne(int blockID, int local); + + /** + * Add this local to liveKill if it wasn't already generated in this block. + */ + protected abstract void storeOne(int blockID, int local); + + private void computeLocalLiveness(BytecodeStream stream, BciBlock block) { + if (block.startBci < 0 || block.endBci < 0) { + return; + } + int blockID = block.getId(); + int localIndex; + stream.setBCI(block.startBci); + while (stream.currentBCI() <= block.endBci) { + switch (stream.currentBC()) { + case LLOAD: + case DLOAD: + loadTwo(blockID, stream.readLocalIndex()); + break; + case LLOAD_0: + case DLOAD_0: + loadTwo(blockID, 0); + break; + case LLOAD_1: + case DLOAD_1: + loadTwo(blockID, 1); + break; + case LLOAD_2: + case DLOAD_2: + loadTwo(blockID, 2); + break; + case LLOAD_3: + case DLOAD_3: + loadTwo(blockID, 3); + break; + case IINC: + localIndex = stream.readLocalIndex(); + loadOne(blockID, localIndex); + storeOne(blockID, localIndex); + break; + case ILOAD: + case FLOAD: + case ALOAD: + case RET: + loadOne(blockID, stream.readLocalIndex()); + break; + case ILOAD_0: + case FLOAD_0: + case ALOAD_0: + loadOne(blockID, 0); + break; + case ILOAD_1: + case FLOAD_1: + case ALOAD_1: + loadOne(blockID, 1); + break; + case ILOAD_2: + case FLOAD_2: + case ALOAD_2: + loadOne(blockID, 2); + break; + case ILOAD_3: + case FLOAD_3: + case ALOAD_3: + loadOne(blockID, 3); + break; + + case LSTORE: + case DSTORE: + storeTwo(blockID, stream.readLocalIndex()); + break; + case LSTORE_0: + case DSTORE_0: + storeTwo(blockID, 0); + break; + case LSTORE_1: + case DSTORE_1: + storeTwo(blockID, 1); + break; + case LSTORE_2: + case DSTORE_2: + storeTwo(blockID, 2); + break; + case LSTORE_3: + case DSTORE_3: + storeTwo(blockID, 3); + break; + case ISTORE: + case FSTORE: + case ASTORE: + storeOne(blockID, stream.readLocalIndex()); + break; + case ISTORE_0: + case FSTORE_0: + case ASTORE_0: + storeOne(blockID, 0); + break; + case ISTORE_1: + case FSTORE_1: + case ASTORE_1: + storeOne(blockID, 1); + break; + case ISTORE_2: + case FSTORE_2: + case ASTORE_2: + storeOne(blockID, 2); + break; + case ISTORE_3: + case FSTORE_3: + case ASTORE_3: + storeOne(blockID, 3); + break; + } + stream.next(); + } + } + + private void loadTwo(int blockID, int local) { + loadOne(blockID, local); + loadOne(blockID, local + 1); + } + + private void storeTwo(int blockID, int local) { + storeOne(blockID, local); + storeOne(blockID, local + 1); + } +}