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