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