1 /* 2 * Copyright (c) 2009, 2018, 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 24 25 package org.graalvm.compiler.java; 26 27 import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; 28 import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE; 29 import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY; 30 import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN; 31 import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH; 32 import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW; 33 import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD; 34 import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE; 35 import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD; 36 import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE; 37 import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST; 38 import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD; 39 import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE; 40 import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN; 41 import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD; 42 import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE; 43 import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN; 44 import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD; 45 import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC; 46 import static org.graalvm.compiler.bytecode.Bytecodes.GOTO; 47 import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W; 48 import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD; 49 import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE; 50 import static org.graalvm.compiler.bytecode.Bytecodes.IDIV; 51 import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ; 52 import static org.graalvm.compiler.bytecode.Bytecodes.IFGE; 53 import static org.graalvm.compiler.bytecode.Bytecodes.IFGT; 54 import static org.graalvm.compiler.bytecode.Bytecodes.IFLE; 55 import static org.graalvm.compiler.bytecode.Bytecodes.IFLT; 56 import static org.graalvm.compiler.bytecode.Bytecodes.IFNE; 57 import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL; 58 import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL; 59 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ; 60 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE; 61 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ; 62 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE; 63 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT; 64 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE; 65 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT; 66 import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE; 67 import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC; 68 import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE; 69 import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL; 70 import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC; 71 import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL; 72 import static org.graalvm.compiler.bytecode.Bytecodes.IREM; 73 import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN; 74 import static org.graalvm.compiler.bytecode.Bytecodes.JSR; 75 import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W; 76 import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD; 77 import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE; 78 import static org.graalvm.compiler.bytecode.Bytecodes.LDC; 79 import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W; 80 import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W; 81 import static org.graalvm.compiler.bytecode.Bytecodes.LDIV; 82 import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH; 83 import static org.graalvm.compiler.bytecode.Bytecodes.LREM; 84 import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN; 85 import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY; 86 import static org.graalvm.compiler.bytecode.Bytecodes.NEW; 87 import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD; 88 import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC; 89 import static org.graalvm.compiler.bytecode.Bytecodes.RET; 90 import static org.graalvm.compiler.bytecode.Bytecodes.RETURN; 91 import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD; 92 import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE; 93 import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; 94 import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes; 95 96 import java.util.ArrayList; 97 import java.util.Arrays; 98 import java.util.Collection; 99 import java.util.Iterator; 100 import java.util.List; 101 import java.util.TreeSet; 102 103 import jdk.internal.vm.compiler.collections.EconomicMap; 104 import jdk.internal.vm.compiler.collections.Equivalence; 105 import org.graalvm.compiler.bytecode.Bytecode; 106 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; 107 import org.graalvm.compiler.bytecode.BytecodeStream; 108 import org.graalvm.compiler.bytecode.BytecodeSwitch; 109 import org.graalvm.compiler.bytecode.BytecodeTableSwitch; 110 import org.graalvm.compiler.bytecode.Bytecodes; 111 import org.graalvm.compiler.core.common.PermanentBailoutException; 112 import org.graalvm.compiler.debug.DebugContext; 113 import org.graalvm.compiler.options.OptionValues; 114 115 import jdk.vm.ci.code.BytecodeFrame; 116 import jdk.vm.ci.meta.ExceptionHandler; 117 118 /** 119 * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph 120 * (CFG). It makes one linear passes over the bytecodes to build the CFG where it detects block 121 * headers and connects them. 122 * <p> 123 * It also creates exception dispatch blocks for exception handling. These blocks are between a 124 * bytecode that might throw an exception, and the actual exception handler entries, and are later 125 * used to create the type checks with the exception handler catch types. If a bytecode is covered 126 * by an exception handler, this bytecode ends the basic block. This guarantees that a) control flow 127 * cannot be transferred to an exception dispatch block in the middle of a block, and b) that every 128 * block has at most one exception dispatch block (which is always the last entry in the successor 129 * list). 130 * <p> 131 * If a bytecode is covered by multiple exception handlers, a chain of exception dispatch blocks is 132 * created so that multiple exception handler types can be checked. The chains are re-used if 133 * multiple bytecodes are covered by the same exception handlers. 134 * <p> 135 * Note that exception unwinds, i.e., bytecodes that can throw an exception but the exception is not 136 * handled in this method, do not end a basic block. Not modeling the exception unwind block reduces 137 * the complexity of the CFG, and there is no algorithm yet where the exception unwind block would 138 * matter. 139 * <p> 140 * The class also handles subroutines (jsr and ret bytecodes): subroutines are inlined by 141 * duplicating the subroutine blocks. This is limited to simple, structured subroutines with a 142 * maximum subroutine nesting of 4. Otherwise, a bailout is thrown. 143 * <p> 144 * Loops in the methods are detected. If a method contains an irreducible loop (a loop with more 145 * than one entry), a bailout is thrown. This simplifies the compiler later on since only structured 146 * loops need to be supported. 147 * <p> 148 * A data flow analysis computes the live local variables from the point of view of the interpreter. 149 * The result is used later to prune frame states, i.e., remove local variable entries that are 150 * guaranteed to be never used again (even in the case of deoptimization). 151 * <p> 152 * The algorithms and analysis in this class are conservative and do not use any assumptions or 153 * profiling information. 154 */ 155 public final class BciBlockMapping { 156 157 public static class BciBlock implements Cloneable { 158 159 int id; 160 final int startBci; 161 int endBci; 162 private boolean isExceptionEntry; 163 private boolean isLoopHeader; 164 int loopId; 165 int loopEnd; 166 List<BciBlock> successors; 167 private int predecessorCount; 168 169 private boolean visited; 170 private boolean active; 171 long loops; 172 JSRData jsrData; 173 174 public static class JSRData implements Cloneable { 175 public EconomicMap<JsrScope, BciBlock> jsrAlternatives; 176 public JsrScope jsrScope = JsrScope.EMPTY_SCOPE; 177 public BciBlock jsrSuccessor; 178 public int jsrReturnBci; 179 public BciBlock retSuccessor; 180 public boolean endsWithRet = false; 181 182 public JSRData copy() { 183 try { 184 return (JSRData) this.clone(); 185 } catch (CloneNotSupportedException e) { 186 return null; 187 } 188 } 189 } 190 191 BciBlock(int startBci) { 192 this.startBci = startBci; 193 this.successors = new ArrayList<>(); 194 } 195 196 public int getStartBci() { 197 return startBci; 198 } 199 200 public int getEndBci() { 201 return endBci; 202 } 203 204 public long getLoops() { 205 return loops; 206 } 207 208 public BciBlock exceptionDispatchBlock() { 209 if (successors.size() > 0 && successors.get(successors.size() - 1) instanceof ExceptionDispatchBlock) { 210 return successors.get(successors.size() - 1); 211 } 212 return null; 213 } 214 215 public int getId() { 216 return id; 217 } 218 219 public int getPredecessorCount() { 220 return this.predecessorCount; 221 } 222 223 public int numNormalSuccessors() { 224 if (exceptionDispatchBlock() != null) { 225 return successors.size() - 1; 226 } 227 return successors.size(); 228 } 229 230 public BciBlock copy() { 231 try { 232 BciBlock block = (BciBlock) super.clone(); 233 if (block.jsrData != null) { 234 block.jsrData = block.jsrData.copy(); 235 } 236 block.successors = new ArrayList<>(successors); 237 return block; 238 } catch (CloneNotSupportedException e) { 239 throw new RuntimeException(e); 240 } 241 } 242 243 @Override 244 public String toString() { 245 StringBuilder sb = new StringBuilder("B").append(getId()); 246 sb.append('[').append(startBci).append("..").append(endBci); 247 if (isLoopHeader || isExceptionEntry || this instanceof ExceptionDispatchBlock) { 248 sb.append(' '); 249 if (isLoopHeader) { 250 sb.append('L'); 251 } 252 if (isExceptionEntry) { 253 sb.append('!'); 254 } else if (this instanceof ExceptionDispatchBlock) { 255 sb.append("<!>"); 256 } 257 } 258 sb.append(']'); 259 return sb.toString(); 260 } 261 262 public int getLoopDepth() { 263 return Long.bitCount(loops); 264 } 265 266 public boolean isLoopHeader() { 267 return isLoopHeader; 268 } 269 270 public boolean isExceptionEntry() { 271 return isExceptionEntry; 272 } 273 274 public BciBlock getSuccessor(int index) { 275 return successors.get(index); 276 } 277 278 /** 279 * Get the loop id of the inner most loop. 280 * 281 * @return the loop id of the most inner loop or -1 if not part of any loop 282 */ 283 public int getLoopId() { 284 long l = loops; 285 if (l == 0) { 286 return -1; 287 } 288 int pos = 0; 289 for (int lMask = 1; (l & lMask) == 0; lMask = lMask << 1) { 290 pos++; 291 } 292 return pos; 293 } 294 295 /** 296 * Iterate over loop ids. 297 */ 298 public Iterable<Integer> loopIdIterable() { 299 return new Iterable<Integer>() { 300 @Override 301 public Iterator<Integer> iterator() { 302 return idIterator(loops); 303 } 304 }; 305 } 306 307 private static Iterator<Integer> idIterator(long field) { 308 return new Iterator<Integer>() { 309 310 long l = field; 311 int pos = 0; 312 int lMask = 1; 313 314 @Override 315 public Integer next() { 316 for (; (l & lMask) == 0; lMask = lMask << 1) { 317 pos++; 318 } 319 l &= ~lMask; 320 return pos; 321 } 322 323 @Override 324 public boolean hasNext() { 325 return l != 0; 326 } 327 }; 328 329 } 330 331 public double probability() { 332 return 1D; 333 } 334 335 public BciBlock getPostdominator() { 336 return null; 337 } 338 339 private JSRData getOrCreateJSRData() { 340 if (jsrData == null) { 341 jsrData = new JSRData(); 342 } 343 return jsrData; 344 } 345 346 void setEndsWithRet() { 347 getOrCreateJSRData().endsWithRet = true; 348 } 349 350 public JsrScope getJsrScope() { 351 if (this.jsrData == null) { 352 return JsrScope.EMPTY_SCOPE; 353 } else { 354 return jsrData.jsrScope; 355 } 356 } 357 358 public boolean endsWithRet() { 359 if (this.jsrData == null) { 360 return false; 361 } else { 362 return jsrData.endsWithRet; 363 } 364 } 365 366 void setRetSuccessor(BciBlock bciBlock) { 367 this.getOrCreateJSRData().retSuccessor = bciBlock; 368 } 369 370 public BciBlock getRetSuccessor() { 371 if (this.jsrData == null) { 372 return null; 373 } else { 374 return jsrData.retSuccessor; 375 } 376 } 377 378 public BciBlock getJsrSuccessor() { 379 if (this.jsrData == null) { 380 return null; 381 } else { 382 return jsrData.jsrSuccessor; 383 } 384 } 385 386 public int getJsrReturnBci() { 387 if (this.jsrData == null) { 388 return -1; 389 } else { 390 return jsrData.jsrReturnBci; 391 } 392 } 393 394 public EconomicMap<JsrScope, BciBlock> getJsrAlternatives() { 395 if (this.jsrData == null) { 396 return null; 397 } else { 398 return jsrData.jsrAlternatives; 399 } 400 } 401 402 public void initJsrAlternatives() { 403 JSRData data = this.getOrCreateJSRData(); 404 if (data.jsrAlternatives == null) { 405 data.jsrAlternatives = EconomicMap.create(Equivalence.DEFAULT); 406 } 407 } 408 409 void setJsrScope(JsrScope nextScope) { 410 this.getOrCreateJSRData().jsrScope = nextScope; 411 } 412 413 void setJsrSuccessor(BciBlock clone) { 414 this.getOrCreateJSRData().jsrSuccessor = clone; 415 } 416 417 void setJsrReturnBci(int bci) { 418 this.getOrCreateJSRData().jsrReturnBci = bci; 419 } 420 421 public int getSuccessorCount() { 422 return successors.size(); 423 } 424 425 public List<BciBlock> getSuccessors() { 426 return successors; 427 } 428 429 void setId(int i) { 430 this.id = i; 431 } 432 433 public void addSuccessor(BciBlock sux) { 434 successors.add(sux); 435 sux.predecessorCount++; 436 } 437 438 public void clearSucccessors() { 439 for (BciBlock sux : successors) { 440 sux.predecessorCount--; 441 } 442 successors.clear(); 443 } 444 445 public boolean isExceptionDispatch() { 446 return false; 447 } 448 } 449 450 public static class ExceptionDispatchBlock extends BciBlock { 451 public final ExceptionHandler handler; 452 public final int deoptBci; 453 454 /** 455 * Constructor for a normal dispatcher. 456 */ 457 ExceptionDispatchBlock(ExceptionHandler handler, int deoptBci) { 458 super(handler.getHandlerBCI()); 459 this.endBci = startBci; 460 this.deoptBci = deoptBci; 461 this.handler = handler; 462 } 463 464 /** 465 * Constructor for the method unwind dispatcher. 466 */ 467 ExceptionDispatchBlock(int deoptBci) { 468 super(deoptBci); 469 this.endBci = deoptBci; 470 this.deoptBci = deoptBci; 471 this.handler = null; 472 } 473 474 @Override 475 public boolean isExceptionDispatch() { 476 return true; 477 } 478 } 479 480 /** 481 * The blocks found in this method, in reverse postorder. 482 */ 483 private BciBlock[] blocks; 484 public final Bytecode code; 485 public boolean hasJsrBytecodes; 486 487 private final ExceptionHandler[] exceptionHandlers; 488 private BciBlock startBlock; 489 private BciBlock[] loopHeaders; 490 491 private static final int LOOP_HEADER_MAX_CAPACITY = Long.SIZE; 492 private static final int LOOP_HEADER_INITIAL_CAPACITY = 4; 493 494 private int blocksNotYetAssignedId; 495 private final DebugContext debug; 496 497 /** 498 * Creates a new BlockMap instance from {@code code}. 499 */ 500 private BciBlockMapping(Bytecode code, DebugContext debug) { 501 this.code = code; 502 this.debug = debug; 503 this.exceptionHandlers = code.getExceptionHandlers(); 504 } 505 506 public BciBlock[] getBlocks() { 507 return this.blocks; 508 } 509 510 /** 511 * Builds the block map and conservative CFG and numbers blocks. 512 */ 513 public void build(BytecodeStream stream, OptionValues options) { 514 int codeSize = code.getCodeSize(); 515 BciBlock[] blockMap = new BciBlock[codeSize]; 516 makeExceptionEntries(blockMap); 517 iterateOverBytecodes(blockMap, stream); 518 if (hasJsrBytecodes) { 519 if (!SupportJsrBytecodes.getValue(options)) { 520 throw new JsrNotSupportedBailout("jsr/ret parsing disabled"); 521 } 522 createJsrAlternatives(blockMap, blockMap[0]); 523 } 524 if (debug.isLogEnabled()) { 525 this.log(blockMap, "Before BlockOrder"); 526 } 527 computeBlockOrder(blockMap); 528 fixLoopBits(blockMap); 529 530 assert verify(); 531 532 startBlock = blockMap[0]; 533 if (debug.isLogEnabled()) { 534 this.log(blockMap, "Before LivenessAnalysis"); 535 } 536 } 537 538 private boolean verify() { 539 for (BciBlock block : blocks) { 540 assert blocks[block.getId()] == block; 541 for (int i = 0; i < block.getSuccessorCount(); i++) { 542 BciBlock sux = block.getSuccessor(i); 543 if (sux instanceof ExceptionDispatchBlock) { 544 assert i == block.getSuccessorCount() - 1 : "Only one exception handler allowed, and it must be last in successors list"; 545 } 546 } 547 } 548 549 return true; 550 } 551 552 private void makeExceptionEntries(BciBlock[] blockMap) { 553 // start basic blocks at all exception handler blocks and mark them as exception entries 554 for (ExceptionHandler h : this.exceptionHandlers) { 555 BciBlock xhandler = makeBlock(blockMap, h.getHandlerBCI()); 556 xhandler.isExceptionEntry = true; 557 } 558 } 559 560 private void iterateOverBytecodes(BciBlock[] blockMap, BytecodeStream stream) { 561 // iterate over the bytecodes top to bottom. 562 // mark the entrypoints of basic blocks and build lists of successors for 563 // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) 564 BciBlock current = null; 565 stream.setBCI(0); 566 while (stream.currentBC() != Bytecodes.END) { 567 int bci = stream.currentBCI(); 568 569 if (current == null || blockMap[bci] != null) { 570 BciBlock b = makeBlock(blockMap, bci); 571 if (current != null) { 572 addSuccessor(blockMap, current.endBci, b); 573 } 574 current = b; 575 } 576 blockMap[bci] = current; 577 current.endBci = bci; 578 579 switch (stream.currentBC()) { 580 case IRETURN: // fall through 581 case LRETURN: // fall through 582 case FRETURN: // fall through 583 case DRETURN: // fall through 584 case ARETURN: // fall through 585 case RETURN: { 586 current = null; 587 break; 588 } 589 case ATHROW: { 590 current = null; 591 ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); 592 if (handler != null) { 593 addSuccessor(blockMap, bci, handler); 594 } 595 break; 596 } 597 case IFEQ: // fall through 598 case IFNE: // fall through 599 case IFLT: // fall through 600 case IFGE: // fall through 601 case IFGT: // fall through 602 case IFLE: // fall through 603 case IF_ICMPEQ: // fall through 604 case IF_ICMPNE: // fall through 605 case IF_ICMPLT: // fall through 606 case IF_ICMPGE: // fall through 607 case IF_ICMPGT: // fall through 608 case IF_ICMPLE: // fall through 609 case IF_ACMPEQ: // fall through 610 case IF_ACMPNE: // fall through 611 case IFNULL: // fall through 612 case IFNONNULL: { 613 current = null; 614 addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest())); 615 addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); 616 break; 617 } 618 case GOTO: 619 case GOTO_W: { 620 current = null; 621 addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest())); 622 break; 623 } 624 case TABLESWITCH: { 625 current = null; 626 addSwitchSuccessors(blockMap, bci, new BytecodeTableSwitch(stream, bci)); 627 break; 628 } 629 case LOOKUPSWITCH: { 630 current = null; 631 addSwitchSuccessors(blockMap, bci, new BytecodeLookupSwitch(stream, bci)); 632 break; 633 } 634 case JSR: 635 case JSR_W: { 636 hasJsrBytecodes = true; 637 int target = stream.readBranchDest(); 638 if (target == 0) { 639 throw new JsrNotSupportedBailout("jsr target bci 0 not allowed"); 640 } 641 BciBlock b1 = makeBlock(blockMap, target); 642 current.setJsrSuccessor(b1); 643 current.setJsrReturnBci(stream.nextBCI()); 644 current = null; 645 addSuccessor(blockMap, bci, b1); 646 break; 647 } 648 case RET: { 649 current.setEndsWithRet(); 650 current = null; 651 break; 652 } 653 case INVOKEINTERFACE: 654 case INVOKESPECIAL: 655 case INVOKESTATIC: 656 case INVOKEVIRTUAL: 657 case INVOKEDYNAMIC: { 658 current = null; 659 addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); 660 ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); 661 if (handler != null) { 662 addSuccessor(blockMap, bci, handler); 663 } 664 break; 665 } 666 case IDIV: 667 case IREM: 668 case LDIV: 669 case LREM: 670 case IASTORE: 671 case LASTORE: 672 case FASTORE: 673 case DASTORE: 674 case AASTORE: 675 case BASTORE: 676 case CASTORE: 677 case SASTORE: 678 case IALOAD: 679 case LALOAD: 680 case FALOAD: 681 case DALOAD: 682 case AALOAD: 683 case BALOAD: 684 case CALOAD: 685 case SALOAD: 686 case ARRAYLENGTH: 687 case CHECKCAST: 688 case NEW: 689 case ANEWARRAY: 690 case MULTIANEWARRAY: 691 case PUTSTATIC: 692 case GETSTATIC: 693 case PUTFIELD: 694 case GETFIELD: 695 case LDC: 696 case LDC_W: 697 case LDC2_W: { 698 /* 699 * All bytecodes that can trigger lazy class initialization via a 700 * ClassInitializationPlugin (allocations, static field access) must be listed 701 * because the class initializer is allowed to throw an exception, which 702 * requires proper exception handling. 703 */ 704 ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); 705 if (handler != null) { 706 current = null; 707 addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI())); 708 addSuccessor(blockMap, bci, handler); 709 } 710 } 711 } 712 stream.next(); 713 } 714 } 715 716 private BciBlock makeBlock(BciBlock[] blockMap, int startBci) { 717 BciBlock oldBlock = blockMap[startBci]; 718 if (oldBlock == null) { 719 BciBlock newBlock = new BciBlock(startBci); 720 blocksNotYetAssignedId++; 721 blockMap[startBci] = newBlock; 722 return newBlock; 723 724 } else if (oldBlock.startBci != startBci) { 725 // Backward branch into the middle of an already processed block. 726 // Add the correct fall-through successor. 727 BciBlock newBlock = new BciBlock(startBci); 728 blocksNotYetAssignedId++; 729 newBlock.endBci = oldBlock.endBci; 730 for (BciBlock oldSuccessor : oldBlock.getSuccessors()) { 731 newBlock.addSuccessor(oldSuccessor); 732 } 733 734 oldBlock.endBci = startBci - 1; 735 oldBlock.clearSucccessors(); 736 oldBlock.addSuccessor(newBlock); 737 738 for (int i = startBci; i <= newBlock.endBci; i++) { 739 blockMap[i] = newBlock; 740 } 741 return newBlock; 742 743 } else { 744 return oldBlock; 745 } 746 } 747 748 private void addSwitchSuccessors(BciBlock[] blockMap, int predBci, BytecodeSwitch bswitch) { 749 // adds distinct targets to the successor list 750 Collection<Integer> targets = new TreeSet<>(); 751 for (int i = 0; i < bswitch.numberOfCases(); i++) { 752 targets.add(bswitch.targetAt(i)); 753 } 754 targets.add(bswitch.defaultTarget()); 755 for (int targetBci : targets) { 756 addSuccessor(blockMap, predBci, makeBlock(blockMap, targetBci)); 757 } 758 } 759 760 private static void addSuccessor(BciBlock[] blockMap, int predBci, BciBlock sux) { 761 BciBlock predecessor = blockMap[predBci]; 762 if (sux.isExceptionEntry) { 763 throw new PermanentBailoutException("Exception handler can be reached by both normal and exceptional control flow"); 764 } 765 predecessor.addSuccessor(sux); 766 } 767 768 private final ArrayList<BciBlock> jsrVisited = new ArrayList<>(); 769 770 private void createJsrAlternatives(BciBlock[] blockMap, BciBlock block) { 771 jsrVisited.add(block); 772 JsrScope scope = block.getJsrScope(); 773 774 if (block.endsWithRet()) { 775 block.setRetSuccessor(blockMap[scope.nextReturnAddress()]); 776 block.addSuccessor(block.getRetSuccessor()); 777 assert block.getRetSuccessor() != block.getJsrSuccessor(); 778 } 779 debug.log("JSR alternatives block %s sux %s jsrSux %s retSux %s jsrScope %s", block, block.getSuccessors(), block.getJsrSuccessor(), block.getRetSuccessor(), block.getJsrScope()); 780 781 if (block.getJsrSuccessor() != null || !scope.isEmpty()) { 782 for (int i = 0; i < block.getSuccessorCount(); i++) { 783 BciBlock successor = block.getSuccessor(i); 784 JsrScope nextScope = scope; 785 if (successor == block.getJsrSuccessor()) { 786 nextScope = scope.push(block.getJsrReturnBci()); 787 } 788 if (successor == block.getRetSuccessor()) { 789 nextScope = scope.pop(); 790 } 791 if (!successor.getJsrScope().isPrefixOf(nextScope)) { 792 throw new JsrNotSupportedBailout("unstructured control flow (" + successor.getJsrScope() + " " + nextScope + ")"); 793 } 794 if (!nextScope.isEmpty()) { 795 BciBlock clone; 796 if (successor.getJsrAlternatives() != null && successor.getJsrAlternatives().containsKey(nextScope)) { 797 clone = successor.getJsrAlternatives().get(nextScope); 798 } else { 799 successor.initJsrAlternatives(); 800 clone = successor.copy(); 801 blocksNotYetAssignedId++; 802 clone.setJsrScope(nextScope); 803 successor.getJsrAlternatives().put(nextScope, clone); 804 } 805 block.getSuccessors().set(i, clone); 806 if (successor == block.getJsrSuccessor()) { 807 block.setJsrSuccessor(clone); 808 } 809 if (successor == block.getRetSuccessor()) { 810 block.setRetSuccessor(clone); 811 } 812 } 813 } 814 } 815 for (BciBlock successor : block.getSuccessors()) { 816 if (!jsrVisited.contains(successor)) { 817 createJsrAlternatives(blockMap, successor); 818 } 819 } 820 } 821 822 private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) { 823 ExceptionDispatchBlock lastHandler = null; 824 int dispatchBlocks = 0; 825 826 for (int i = exceptionHandlers.length - 1; i >= 0; i--) { 827 ExceptionHandler h = exceptionHandlers[i]; 828 if (h.getStartBCI() <= bci && bci < h.getEndBCI()) { 829 if (h.isCatchAll()) { 830 // Discard all information about succeeding exception handlers, since they can 831 // never be reached. 832 dispatchBlocks = 0; 833 lastHandler = null; 834 } 835 836 // We do not reuse exception dispatch blocks, because nested exception handlers 837 // might have problems reasoning about the correct frame state. 838 ExceptionDispatchBlock curHandler = new ExceptionDispatchBlock(h, bci); 839 dispatchBlocks++; 840 curHandler.addSuccessor(blockMap[h.getHandlerBCI()]); 841 if (lastHandler != null) { 842 curHandler.addSuccessor(lastHandler); 843 } 844 lastHandler = curHandler; 845 } 846 } 847 blocksNotYetAssignedId += dispatchBlocks; 848 return lastHandler; 849 } 850 851 private boolean loopChanges; 852 853 private void fixLoopBits(BciBlock[] blockMap) { 854 do { 855 loopChanges = false; 856 for (BciBlock b : blocks) { 857 b.visited = false; 858 } 859 860 long loop = fixLoopBits(blockMap, blockMap[0]); 861 862 if (loop != 0) { 863 // There is a path from a loop end to the method entry that does not pass the loop 864 // header. 865 // Therefore, the loop is non reducible (has more than one entry). 866 // We don't want to compile such methods because the IR only supports structured 867 // loops. 868 throw new PermanentBailoutException("Non-reducible loop: %016x", loop); 869 } 870 } while (loopChanges); 871 } 872 873 private void computeBlockOrder(BciBlock[] blockMap) { 874 int maxBlocks = blocksNotYetAssignedId; 875 this.blocks = new BciBlock[blocksNotYetAssignedId]; 876 long loop = computeBlockOrder(blockMap[0]); 877 878 if (loop != 0) { 879 // There is a path from a loop end to the method entry that does not pass the loop 880 // header. Therefore, the loop is non reducible (has more than one entry). 881 // We don't want to compile such methods because the IR only supports structured loops. 882 throw new PermanentBailoutException("Non-reducible loop"); 883 } 884 885 // Purge null entries for unreached blocks and sort blocks such that loop bodies are always 886 // consecutively in the array. 887 int blockCount = maxBlocks - blocksNotYetAssignedId + 1; 888 BciBlock[] newBlocks = new BciBlock[blockCount]; 889 int next = 0; 890 for (int i = 0; i < blocks.length; ++i) { 891 BciBlock b = blocks[i]; 892 if (b != null) { 893 b.setId(next); 894 newBlocks[next++] = b; 895 if (b.isLoopHeader) { 896 next = handleLoopHeader(newBlocks, next, i, b); 897 } 898 } 899 } 900 assert next == newBlocks.length - 1; 901 902 // Add unwind block. 903 ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock(BytecodeFrame.AFTER_EXCEPTION_BCI); 904 unwindBlock.setId(newBlocks.length - 1); 905 newBlocks[newBlocks.length - 1] = unwindBlock; 906 907 blocks = newBlocks; 908 } 909 910 private int handleLoopHeader(BciBlock[] newBlocks, int nextStart, int i, BciBlock loopHeader) { 911 int next = nextStart; 912 int endOfLoop = nextStart - 1; 913 for (int j = i + 1; j < blocks.length; ++j) { 914 BciBlock other = blocks[j]; 915 if (other != null && (other.loops & (1L << loopHeader.loopId)) != 0) { 916 other.setId(next); 917 endOfLoop = next; 918 newBlocks[next++] = other; 919 blocks[j] = null; 920 if (other.isLoopHeader) { 921 next = handleLoopHeader(newBlocks, next, j, other); 922 } 923 } 924 } 925 loopHeader.loopEnd = endOfLoop; 926 return next; 927 } 928 929 public void log(BciBlock[] blockMap, String name) { 930 if (debug.isLogEnabled()) { 931 debug.log("%sBlockMap %s: %n%s", debug.getCurrentScopeName(), name, toString(blockMap, loopHeaders)); 932 } 933 } 934 935 public static String toString(BciBlock[] blockMap, BciBlock[] loopHeadersMap) { 936 StringBuilder sb = new StringBuilder(); 937 for (BciBlock b : blockMap) { 938 if (b == null) { 939 continue; 940 } 941 sb.append("B").append(b.getId()).append("[").append(b.startBci).append("..").append(b.endBci).append("]"); 942 if (b.isLoopHeader) { 943 sb.append(" LoopHeader"); 944 } 945 if (b.isExceptionEntry) { 946 sb.append(" ExceptionEntry"); 947 } 948 if (b instanceof ExceptionDispatchBlock) { 949 sb.append(" ExceptionDispatch"); 950 } 951 if (!b.successors.isEmpty()) { 952 sb.append(" Successors=["); 953 for (BciBlock s : b.getSuccessors()) { 954 if (sb.charAt(sb.length() - 1) != '[') { 955 sb.append(", "); 956 } 957 sb.append("B").append(s.getId()); 958 } 959 sb.append("]"); 960 } 961 if (b.loops != 0L) { 962 sb.append(" Loops=["); 963 for (int pos : b.loopIdIterable()) { 964 if (sb.charAt(sb.length() - 1) == '[') { 965 sb.append(", "); 966 } 967 sb.append("B").append(loopHeadersMap[pos].getId()); 968 } 969 sb.append("]"); 970 } 971 sb.append(System.lineSeparator()); 972 } 973 return sb.toString(); 974 } 975 976 @Override 977 public String toString() { 978 return toString(blocks, loopHeaders); 979 } 980 981 /** 982 * Get the header block for a loop index. 983 */ 984 public BciBlock getLoopHeader(int index) { 985 return loopHeaders[index]; 986 } 987 988 /** 989 * The next available loop number. 990 */ 991 private int nextLoop; 992 993 /** 994 * Mark the block as a loop header, using the next available loop number. Also checks for corner 995 * cases that we don't want to compile. 996 */ 997 private void makeLoopHeader(BciBlock block) { 998 if (!block.isLoopHeader) { 999 block.isLoopHeader = true; 1000 1001 if (block.isExceptionEntry) { 1002 // Loops that are implicitly formed by an exception handler lead to all sorts of 1003 // corner cases. 1004 // Don't compile such methods for now, until we see a concrete case that allows 1005 // checking for correctness. 1006 throw new PermanentBailoutException("Loop formed by an exception handler"); 1007 } 1008 if (nextLoop >= LOOP_HEADER_MAX_CAPACITY) { 1009 // This restriction can be removed by using a fall-back to a BitSet in case we have 1010 // more than 64 loops 1011 // Don't compile such methods for now, until we see a concrete case that allows 1012 // checking for correctness. 1013 throw new PermanentBailoutException("Too many loops in method"); 1014 } 1015 1016 assert block.loops == 0; 1017 block.loops = 1L << nextLoop; 1018 debug.log("makeLoopHeader(%s) -> %x", block, block.loops); 1019 if (loopHeaders == null) { 1020 loopHeaders = new BciBlock[LOOP_HEADER_INITIAL_CAPACITY]; 1021 } else if (nextLoop >= loopHeaders.length) { 1022 loopHeaders = Arrays.copyOf(loopHeaders, LOOP_HEADER_MAX_CAPACITY); 1023 } 1024 loopHeaders[nextLoop] = block; 1025 block.loopId = nextLoop; 1026 nextLoop++; 1027 } 1028 assert Long.bitCount(block.loops) == 1; 1029 } 1030 1031 /** 1032 * Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is 1033 * used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect 1034 * cycles (backward edges). 1035 */ 1036 private long computeBlockOrder(BciBlock block) { 1037 if (block.visited) { 1038 if (block.active) { 1039 // Reached block via backward branch. 1040 makeLoopHeader(block); 1041 // Return cached loop information for this block. 1042 return block.loops; 1043 } else if (block.isLoopHeader) { 1044 return block.loops & ~(1L << block.loopId); 1045 } else { 1046 return block.loops; 1047 } 1048 } 1049 1050 block.visited = true; 1051 block.active = true; 1052 1053 long loops = 0; 1054 for (BciBlock successor : block.getSuccessors()) { 1055 // Recursively process successors. 1056 loops |= computeBlockOrder(successor); 1057 if (successor.active) { 1058 // Reached block via backward branch. 1059 loops |= (1L << successor.loopId); 1060 } 1061 } 1062 1063 block.loops = loops; 1064 debug.log("computeBlockOrder(%s) -> %x", block, block.loops); 1065 1066 if (block.isLoopHeader) { 1067 loops &= ~(1L << block.loopId); 1068 } 1069 1070 block.active = false; 1071 blocksNotYetAssignedId--; 1072 blocks[blocksNotYetAssignedId] = block; 1073 1074 return loops; 1075 } 1076 1077 private long fixLoopBits(BciBlock[] blockMap, BciBlock block) { 1078 if (block.visited) { 1079 // Return cached loop information for this block. 1080 if (block.isLoopHeader) { 1081 return block.loops & ~(1L << block.loopId); 1082 } else { 1083 return block.loops; 1084 } 1085 } 1086 1087 block.visited = true; 1088 long loops = block.loops; 1089 for (BciBlock successor : block.getSuccessors()) { 1090 // Recursively process successors. 1091 loops |= fixLoopBits(blockMap, successor); 1092 } 1093 if (block.loops != loops) { 1094 loopChanges = true; 1095 block.loops = loops; 1096 debug.log("fixLoopBits0(%s) -> %x", block, block.loops); 1097 } 1098 1099 if (block.isLoopHeader) { 1100 loops &= ~(1L << block.loopId); 1101 } 1102 1103 return loops; 1104 } 1105 1106 public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options, DebugContext debug) { 1107 BciBlockMapping map = new BciBlockMapping(code, debug); 1108 map.build(stream, options); 1109 if (debug.isDumpEnabled(DebugContext.INFO_LEVEL)) { 1110 debug.dump(DebugContext.INFO_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)")); 1111 } 1112 1113 return map; 1114 } 1115 1116 public BciBlock[] getLoopHeaders() { 1117 return loopHeaders; 1118 } 1119 1120 public BciBlock getStartBlock() { 1121 return startBlock; 1122 } 1123 1124 public ExceptionDispatchBlock getUnwindBlock() { 1125 return (ExceptionDispatchBlock) blocks[blocks.length - 1]; 1126 } 1127 1128 public int getLoopCount() { 1129 return nextLoop; 1130 } 1131 1132 public int getBlockCount() { 1133 return blocks.length; 1134 } 1135 }