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