/* * 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); } }