1 /* 2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.java; 24 25 import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD; 26 import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0; 27 import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1; 28 import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2; 29 import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3; 30 import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE; 31 import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0; 32 import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1; 33 import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2; 34 import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3; 35 import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD; 36 import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0; 37 import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1; 38 import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2; 39 import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3; 40 import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE; 41 import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0; 42 import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1; 43 import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2; 44 import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3; 45 import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD; 46 import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0; 47 import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1; 48 import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2; 49 import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3; 50 import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE; 51 import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0; 52 import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1; 53 import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2; 54 import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3; 55 import static org.graalvm.compiler.bytecode.Bytecodes.IINC; 56 import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD; 57 import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0; 58 import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1; 59 import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2; 60 import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3; 61 import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE; 62 import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0; 63 import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1; 64 import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2; 65 import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3; 66 import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD; 67 import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0; 68 import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1; 69 import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2; 70 import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3; 71 import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE; 72 import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0; 73 import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1; 74 import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2; 75 import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3; 76 import static org.graalvm.compiler.bytecode.Bytecodes.RET; 77 78 import org.graalvm.compiler.bytecode.BytecodeStream; 79 import org.graalvm.compiler.debug.Debug; 80 import org.graalvm.compiler.java.BciBlockMapping.BciBlock; 81 82 /** 83 * Encapsulates the liveness calculation, so that subclasses for locals ≤ 64 and locals > 64 84 * can be implemented. 85 */ 86 public abstract class LocalLiveness { 87 protected final BciBlock[] blocks; 88 89 public static LocalLiveness compute(BytecodeStream stream, BciBlock[] blocks, int maxLocals, int loopCount) { 90 LocalLiveness liveness = maxLocals <= 64 ? new SmallLocalLiveness(blocks, maxLocals, loopCount) : new LargeLocalLiveness(blocks, maxLocals, loopCount); 91 liveness.computeLiveness(stream); 92 return liveness; 93 } 94 95 protected LocalLiveness(BciBlock[] blocks) { 96 this.blocks = blocks; 97 } 98 99 void computeLiveness(BytecodeStream stream) { 100 for (BciBlock block : blocks) { 101 computeLocalLiveness(stream, block); 102 } 103 104 boolean changed; 105 int iteration = 0; 106 do { 107 assert traceIteration(iteration); 108 changed = false; 109 for (int i = blocks.length - 1; i >= 0; i--) { 110 BciBlock block = blocks[i]; 111 int blockID = block.getId(); 112 assert traceStart(block, blockID); 113 114 boolean blockChanged = (iteration == 0); 115 if (block.getSuccessorCount() > 0) { 116 int oldCardinality = liveOutCardinality(blockID); 117 for (BciBlock sux : block.getSuccessors()) { 118 assert traceSuccessor(sux); 119 propagateLiveness(blockID, sux.getId()); 120 } 121 blockChanged |= (oldCardinality != liveOutCardinality(blockID)); 122 } 123 124 if (blockChanged) { 125 updateLiveness(blockID); 126 assert traceEnd(block, blockID); 127 } 128 changed |= blockChanged; 129 } 130 iteration++; 131 } while (changed); 132 } 133 134 private static boolean traceIteration(int iteration) { 135 Debug.log("Iteration %d", iteration); 136 return true; 137 } 138 139 private boolean traceEnd(BciBlock block, int blockID) { 140 if (Debug.isLogEnabled()) { 141 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), 142 debugLiveKill(blockID)); 143 } 144 return true; 145 } 146 147 private boolean traceSuccessor(BciBlock sux) { 148 if (Debug.isLogEnabled()) { 149 Debug.log(" Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId())); 150 } 151 return true; 152 } 153 154 private boolean traceStart(BciBlock block, int blockID) { 155 if (Debug.isLogEnabled()) { 156 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), 157 debugLiveKill(blockID)); 158 } 159 return true; 160 } 161 162 /** 163 * Returns whether the local is live at the beginning of the given block. 164 */ 165 public abstract boolean localIsLiveIn(BciBlock block, int local); 166 167 /** 168 * Returns whether the local is set in the given loop. 169 */ 170 public abstract boolean localIsChangedInLoop(int loopId, int local); 171 172 /** 173 * Returns whether the local is live at the end of the given block. 174 */ 175 public abstract boolean localIsLiveOut(BciBlock block, int local); 176 177 /** 178 * Returns a string representation of the liveIn values of the given block. 179 */ 180 protected abstract String debugLiveIn(int blockID); 181 182 /** 183 * Returns a string representation of the liveOut values of the given block. 184 */ 185 protected abstract String debugLiveOut(int blockID); 186 187 /** 188 * Returns a string representation of the liveGen values of the given block. 189 */ 190 protected abstract String debugLiveGen(int blockID); 191 192 /** 193 * Returns a string representation of the liveKill values of the given block. 194 */ 195 protected abstract String debugLiveKill(int blockID); 196 197 /** 198 * Returns the number of live locals at the end of the given block. 199 */ 200 protected abstract int liveOutCardinality(int blockID); 201 202 /** 203 * Adds all locals the are in the liveIn of the successor to the liveOut of the block. 204 */ 205 protected abstract void propagateLiveness(int blockID, int successorID); 206 207 /** 208 * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen. 209 */ 210 protected abstract void updateLiveness(int blockID); 211 212 /** 213 * Adds the local to liveGen if it wasn't already killed in this block. 214 */ 215 protected abstract void loadOne(int blockID, int local); 216 217 /** 218 * Add this local to liveKill if it wasn't already generated in this block. 219 */ 220 protected abstract void storeOne(int blockID, int local); 221 222 private void computeLocalLiveness(BytecodeStream stream, BciBlock block) { 223 if (block.startBci < 0 || block.endBci < 0) { 224 return; 225 } 226 int blockID = block.getId(); 227 int localIndex; 228 stream.setBCI(block.startBci); 229 while (stream.currentBCI() <= block.endBci) { 230 switch (stream.currentBC()) { 231 case LLOAD: 232 case DLOAD: 233 loadTwo(blockID, stream.readLocalIndex()); 234 break; 235 case LLOAD_0: 236 case DLOAD_0: 237 loadTwo(blockID, 0); 238 break; 239 case LLOAD_1: 240 case DLOAD_1: 241 loadTwo(blockID, 1); 242 break; 243 case LLOAD_2: 244 case DLOAD_2: 245 loadTwo(blockID, 2); 246 break; 247 case LLOAD_3: 248 case DLOAD_3: 249 loadTwo(blockID, 3); 250 break; 251 case IINC: 252 localIndex = stream.readLocalIndex(); 253 loadOne(blockID, localIndex); 254 storeOne(blockID, localIndex); 255 break; 256 case ILOAD: 257 case FLOAD: 258 case ALOAD: 259 case RET: 260 loadOne(blockID, stream.readLocalIndex()); 261 break; 262 case ILOAD_0: 263 case FLOAD_0: 264 case ALOAD_0: 265 loadOne(blockID, 0); 266 break; 267 case ILOAD_1: 268 case FLOAD_1: 269 case ALOAD_1: 270 loadOne(blockID, 1); 271 break; 272 case ILOAD_2: 273 case FLOAD_2: 274 case ALOAD_2: 275 loadOne(blockID, 2); 276 break; 277 case ILOAD_3: 278 case FLOAD_3: 279 case ALOAD_3: 280 loadOne(blockID, 3); 281 break; 282 283 case LSTORE: 284 case DSTORE: 285 storeTwo(blockID, stream.readLocalIndex()); 286 break; 287 case LSTORE_0: 288 case DSTORE_0: 289 storeTwo(blockID, 0); 290 break; 291 case LSTORE_1: 292 case DSTORE_1: 293 storeTwo(blockID, 1); 294 break; 295 case LSTORE_2: 296 case DSTORE_2: 297 storeTwo(blockID, 2); 298 break; 299 case LSTORE_3: 300 case DSTORE_3: 301 storeTwo(blockID, 3); 302 break; 303 case ISTORE: 304 case FSTORE: 305 case ASTORE: 306 storeOne(blockID, stream.readLocalIndex()); 307 break; 308 case ISTORE_0: 309 case FSTORE_0: 310 case ASTORE_0: 311 storeOne(blockID, 0); 312 break; 313 case ISTORE_1: 314 case FSTORE_1: 315 case ASTORE_1: 316 storeOne(blockID, 1); 317 break; 318 case ISTORE_2: 319 case FSTORE_2: 320 case ASTORE_2: 321 storeOne(blockID, 2); 322 break; 323 case ISTORE_3: 324 case FSTORE_3: 325 case ASTORE_3: 326 storeOne(blockID, 3); 327 break; 328 } 329 stream.next(); 330 } 331 } 332 333 private void loadTwo(int blockID, int local) { 334 loadOne(blockID, local); 335 loadOne(blockID, local + 1); 336 } 337 338 private void storeTwo(int blockID, int local) { 339 storeOne(blockID, local); 340 storeOne(blockID, local + 1); 341 } 342 }