15916df99999ae58f707d829792ef3997546628fdBen Gruver/*
25916df99999ae58f707d829792ef3997546628fdBen Gruver * Copyright 2013, Google Inc.
35916df99999ae58f707d829792ef3997546628fdBen Gruver * All rights reserved.
45916df99999ae58f707d829792ef3997546628fdBen Gruver *
55916df99999ae58f707d829792ef3997546628fdBen Gruver * Redistribution and use in source and binary forms, with or without
65916df99999ae58f707d829792ef3997546628fdBen Gruver * modification, are permitted provided that the following conditions are
75916df99999ae58f707d829792ef3997546628fdBen Gruver * met:
85916df99999ae58f707d829792ef3997546628fdBen Gruver *
95916df99999ae58f707d829792ef3997546628fdBen Gruver *     * Redistributions of source code must retain the above copyright
105916df99999ae58f707d829792ef3997546628fdBen Gruver * notice, this list of conditions and the following disclaimer.
115916df99999ae58f707d829792ef3997546628fdBen Gruver *     * Redistributions in binary form must reproduce the above
125916df99999ae58f707d829792ef3997546628fdBen Gruver * copyright notice, this list of conditions and the following disclaimer
135916df99999ae58f707d829792ef3997546628fdBen Gruver * in the documentation and/or other materials provided with the
145916df99999ae58f707d829792ef3997546628fdBen Gruver * distribution.
155916df99999ae58f707d829792ef3997546628fdBen Gruver *     * Neither the name of Google Inc. nor the names of its
165916df99999ae58f707d829792ef3997546628fdBen Gruver * contributors may be used to endorse or promote products derived from
175916df99999ae58f707d829792ef3997546628fdBen Gruver * this software without specific prior written permission.
185916df99999ae58f707d829792ef3997546628fdBen Gruver *
195916df99999ae58f707d829792ef3997546628fdBen Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205916df99999ae58f707d829792ef3997546628fdBen Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215916df99999ae58f707d829792ef3997546628fdBen Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225916df99999ae58f707d829792ef3997546628fdBen Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235916df99999ae58f707d829792ef3997546628fdBen Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245916df99999ae58f707d829792ef3997546628fdBen Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255916df99999ae58f707d829792ef3997546628fdBen Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265916df99999ae58f707d829792ef3997546628fdBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275916df99999ae58f707d829792ef3997546628fdBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285916df99999ae58f707d829792ef3997546628fdBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295916df99999ae58f707d829792ef3997546628fdBen Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305916df99999ae58f707d829792ef3997546628fdBen Gruver */
315916df99999ae58f707d829792ef3997546628fdBen Gruver
325916df99999ae58f707d829792ef3997546628fdBen Gruverpackage org.jf.dexlib2.writer.util;
335916df99999ae58f707d829792ef3997546628fdBen Gruver
345916df99999ae58f707d829792ef3997546628fdBen Gruverimport com.google.common.collect.Lists;
355916df99999ae58f707d829792ef3997546628fdBen Gruverimport org.jf.dexlib2.base.BaseTryBlock;
365916df99999ae58f707d829792ef3997546628fdBen Gruverimport org.jf.dexlib2.iface.ExceptionHandler;
375916df99999ae58f707d829792ef3997546628fdBen Gruverimport org.jf.dexlib2.iface.TryBlock;
385916df99999ae58f707d829792ef3997546628fdBen Gruverimport org.jf.util.ExceptionWithContext;
395916df99999ae58f707d829792ef3997546628fdBen Gruver
405916df99999ae58f707d829792ef3997546628fdBen Gruverimport javax.annotation.Nonnull;
418c3d16b7ee368c14e805077d047162f3bb434193Ben Gruverimport javax.annotation.Nullable;
425916df99999ae58f707d829792ef3997546628fdBen Gruverimport java.util.Iterator;
435916df99999ae58f707d829792ef3997546628fdBen Gruverimport java.util.List;
445916df99999ae58f707d829792ef3997546628fdBen Gruverimport java.util.NoSuchElementException;
455916df99999ae58f707d829792ef3997546628fdBen Gruver
461bf6f2324541df184689fdb2c0d8188af5221784Ben Gruverpublic class TryListBuilder<EH extends ExceptionHandler>
475916df99999ae58f707d829792ef3997546628fdBen Gruver{
485916df99999ae58f707d829792ef3997546628fdBen Gruver    // Linked list sentinels that don't represent an actual try block
495916df99999ae58f707d829792ef3997546628fdBen Gruver    // Their values are never modified, only their links
501bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    private final MutableTryBlock<EH> listStart;
511bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    private final MutableTryBlock<EH> listEnd;
525916df99999ae58f707d829792ef3997546628fdBen Gruver
535916df99999ae58f707d829792ef3997546628fdBen Gruver    public TryListBuilder() {
541bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        listStart = new MutableTryBlock<EH>(0, 0);
551bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        listEnd = new MutableTryBlock<EH>(0, 0);
565916df99999ae58f707d829792ef3997546628fdBen Gruver        listStart.next = listEnd;
575916df99999ae58f707d829792ef3997546628fdBen Gruver        listEnd.prev = listStart;
585916df99999ae58f707d829792ef3997546628fdBen Gruver    }
595916df99999ae58f707d829792ef3997546628fdBen Gruver
601bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    public static <EH extends ExceptionHandler> List<TryBlock<EH>> massageTryBlocks(
611bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            List<? extends TryBlock<? extends EH>> tryBlocks) {
621bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        TryListBuilder<EH> tlb = new TryListBuilder<EH>();
631bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver
641bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        for (TryBlock<? extends EH> tryBlock: tryBlocks) {
65ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver            int startAddress = tryBlock.getStartCodeAddress();
66ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver            int endAddress = startAddress + tryBlock.getCodeUnitCount();
67ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver
681bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            for (EH exceptionHandler: tryBlock.getExceptionHandlers()) {
691bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                tlb.addHandler(startAddress, endAddress, exceptionHandler);
70ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver            }
71ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver        }
72ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver        return tlb.getTryBlocks();
73ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver    }
74ab73502b60fadc966ba3ace0aa4b62592cf2ae86Ben Gruver
751bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    private static class TryBounds<EH extends ExceptionHandler> {
761bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        @Nonnull public final MutableTryBlock<EH> start;
771bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        @Nonnull public final MutableTryBlock<EH> end;
785916df99999ae58f707d829792ef3997546628fdBen Gruver
791bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public TryBounds(@Nonnull MutableTryBlock<EH> start, @Nonnull MutableTryBlock<EH> end) {
805916df99999ae58f707d829792ef3997546628fdBen Gruver            this.start = start;
815916df99999ae58f707d829792ef3997546628fdBen Gruver            this.end = end;
825916df99999ae58f707d829792ef3997546628fdBen Gruver        }
835916df99999ae58f707d829792ef3997546628fdBen Gruver    }
845916df99999ae58f707d829792ef3997546628fdBen Gruver
855916df99999ae58f707d829792ef3997546628fdBen Gruver    public static class InvalidTryException extends ExceptionWithContext {
865916df99999ae58f707d829792ef3997546628fdBen Gruver        public InvalidTryException(Throwable cause) {
875916df99999ae58f707d829792ef3997546628fdBen Gruver            super(cause);
885916df99999ae58f707d829792ef3997546628fdBen Gruver        }
895916df99999ae58f707d829792ef3997546628fdBen Gruver
905916df99999ae58f707d829792ef3997546628fdBen Gruver        public InvalidTryException(Throwable cause, String message, Object... formatArgs) {
915916df99999ae58f707d829792ef3997546628fdBen Gruver            super(cause, message, formatArgs);
925916df99999ae58f707d829792ef3997546628fdBen Gruver        }
935916df99999ae58f707d829792ef3997546628fdBen Gruver
945916df99999ae58f707d829792ef3997546628fdBen Gruver        public InvalidTryException(String message, Object... formatArgs) {
955916df99999ae58f707d829792ef3997546628fdBen Gruver            super(message, formatArgs);
965916df99999ae58f707d829792ef3997546628fdBen Gruver        }
975916df99999ae58f707d829792ef3997546628fdBen Gruver    }
985916df99999ae58f707d829792ef3997546628fdBen Gruver
991bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    private static class MutableTryBlock<EH extends ExceptionHandler> extends BaseTryBlock<EH> {
1001bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public MutableTryBlock<EH> prev = null;
1011bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public MutableTryBlock<EH> next = null;
1025916df99999ae58f707d829792ef3997546628fdBen Gruver
1035916df99999ae58f707d829792ef3997546628fdBen Gruver        public int startCodeAddress;
1045916df99999ae58f707d829792ef3997546628fdBen Gruver        public int endCodeAddress;
1051bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        @Nonnull public List<EH> exceptionHandlers = Lists.newArrayList();
1065916df99999ae58f707d829792ef3997546628fdBen Gruver
1075916df99999ae58f707d829792ef3997546628fdBen Gruver        public MutableTryBlock(int startCodeAddress, int endCodeAddress) {
1085916df99999ae58f707d829792ef3997546628fdBen Gruver            this.startCodeAddress = startCodeAddress;
1095916df99999ae58f707d829792ef3997546628fdBen Gruver            this.endCodeAddress = endCodeAddress;
1105916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1115916df99999ae58f707d829792ef3997546628fdBen Gruver
1125916df99999ae58f707d829792ef3997546628fdBen Gruver        public MutableTryBlock(int startCodeAddress, int endCodeAddress,
1131bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                               @Nonnull List<EH> exceptionHandlers) {
1145916df99999ae58f707d829792ef3997546628fdBen Gruver            this.startCodeAddress = startCodeAddress;
1155916df99999ae58f707d829792ef3997546628fdBen Gruver            this.endCodeAddress = endCodeAddress;
1165916df99999ae58f707d829792ef3997546628fdBen Gruver            this.exceptionHandlers = Lists.newArrayList(exceptionHandlers);
1175916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1185916df99999ae58f707d829792ef3997546628fdBen Gruver
1195916df99999ae58f707d829792ef3997546628fdBen Gruver        @Override public int getStartCodeAddress() {
1205916df99999ae58f707d829792ef3997546628fdBen Gruver            return startCodeAddress;
1215916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1225916df99999ae58f707d829792ef3997546628fdBen Gruver
1235916df99999ae58f707d829792ef3997546628fdBen Gruver        @Override public int getCodeUnitCount() {
1245916df99999ae58f707d829792ef3997546628fdBen Gruver            return endCodeAddress - startCodeAddress;
1255916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1265916df99999ae58f707d829792ef3997546628fdBen Gruver
1271bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        @Nonnull @Override public List<EH> getExceptionHandlers() {
1285916df99999ae58f707d829792ef3997546628fdBen Gruver            return exceptionHandlers;
1295916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1305916df99999ae58f707d829792ef3997546628fdBen Gruver
1315916df99999ae58f707d829792ef3997546628fdBen Gruver        @Nonnull
1321bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public MutableTryBlock<EH> split(int splitAddress) {
1331bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            MutableTryBlock<EH> newTryBlock = new MutableTryBlock<EH>(splitAddress, endCodeAddress, exceptionHandlers);
1345916df99999ae58f707d829792ef3997546628fdBen Gruver            endCodeAddress = splitAddress;
1355916df99999ae58f707d829792ef3997546628fdBen Gruver            append(newTryBlock);
1365916df99999ae58f707d829792ef3997546628fdBen Gruver            return newTryBlock;
1375916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1385916df99999ae58f707d829792ef3997546628fdBen Gruver
1398c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver        public void delete() {
1408c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            next.prev = prev;
1418c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            prev.next = next;
1428c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver        }
1438c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
1448c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver        public void mergeNext() {
1458c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            //assert next.startCodeAddress == this.endCodeAddress;
1468c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            this.endCodeAddress = next.endCodeAddress;
1478c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            next.delete();
1488c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver        }
1498c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
1501bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public void append(@Nonnull MutableTryBlock<EH> tryBlock) {
1515916df99999ae58f707d829792ef3997546628fdBen Gruver            next.prev = tryBlock;
1525916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock.next = next;
1535916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock.prev = this;
1545916df99999ae58f707d829792ef3997546628fdBen Gruver            next = tryBlock;
1555916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1565916df99999ae58f707d829792ef3997546628fdBen Gruver
1571bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public void prepend(@Nonnull MutableTryBlock<EH> tryBlock) {
1585916df99999ae58f707d829792ef3997546628fdBen Gruver            prev.next = tryBlock;
1595916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock.prev = prev;
1605916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock.next = this;
1615916df99999ae58f707d829792ef3997546628fdBen Gruver            prev = tryBlock;
1625916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1635916df99999ae58f707d829792ef3997546628fdBen Gruver
1641bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        public void addHandler(@Nonnull EH handler) {
1655916df99999ae58f707d829792ef3997546628fdBen Gruver            for (ExceptionHandler existingHandler: exceptionHandlers) {
1665916df99999ae58f707d829792ef3997546628fdBen Gruver                String existingType = existingHandler.getExceptionType();
1675916df99999ae58f707d829792ef3997546628fdBen Gruver                String newType = handler.getExceptionType();
1685916df99999ae58f707d829792ef3997546628fdBen Gruver
1695916df99999ae58f707d829792ef3997546628fdBen Gruver                // Don't add it if we already have a handler of the same type
1705916df99999ae58f707d829792ef3997546628fdBen Gruver                if (existingType == null) {
1715916df99999ae58f707d829792ef3997546628fdBen Gruver                    if (newType == null) {
1725916df99999ae58f707d829792ef3997546628fdBen Gruver                        if (existingHandler.getHandlerCodeAddress() != handler.getHandlerCodeAddress()) {
1735916df99999ae58f707d829792ef3997546628fdBen Gruver                            throw new InvalidTryException(
1745916df99999ae58f707d829792ef3997546628fdBen Gruver                                    "Multiple overlapping catch all handlers with different handlers");
1755916df99999ae58f707d829792ef3997546628fdBen Gruver                        }
1765916df99999ae58f707d829792ef3997546628fdBen Gruver                        return;
1775916df99999ae58f707d829792ef3997546628fdBen Gruver                    }
1785916df99999ae58f707d829792ef3997546628fdBen Gruver                } else if (existingType.equals(newType)) {
1795916df99999ae58f707d829792ef3997546628fdBen Gruver                    if (existingHandler.getHandlerCodeAddress() != handler.getHandlerCodeAddress()) {
1805916df99999ae58f707d829792ef3997546628fdBen Gruver                        throw new InvalidTryException(
1815916df99999ae58f707d829792ef3997546628fdBen Gruver                                "Multiple overlapping catches for %s with different handlers", existingType);
1825916df99999ae58f707d829792ef3997546628fdBen Gruver                    }
1835916df99999ae58f707d829792ef3997546628fdBen Gruver                    return;
1845916df99999ae58f707d829792ef3997546628fdBen Gruver                }
1855916df99999ae58f707d829792ef3997546628fdBen Gruver            }
1865916df99999ae58f707d829792ef3997546628fdBen Gruver
1875916df99999ae58f707d829792ef3997546628fdBen Gruver            exceptionHandlers.add(handler);
1885916df99999ae58f707d829792ef3997546628fdBen Gruver        }
1895916df99999ae58f707d829792ef3997546628fdBen Gruver    }
1905916df99999ae58f707d829792ef3997546628fdBen Gruver
1911bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    private TryBounds<EH> getBoundingRanges(int startAddress, int endAddress) {
1921bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> startBlock = null;
1935916df99999ae58f707d829792ef3997546628fdBen Gruver
1941bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> tryBlock = listStart.next;
1955916df99999ae58f707d829792ef3997546628fdBen Gruver        while (tryBlock != listEnd) {
1965916df99999ae58f707d829792ef3997546628fdBen Gruver            int currentStartAddress = tryBlock.startCodeAddress;
1975916df99999ae58f707d829792ef3997546628fdBen Gruver            int currentEndAddress = tryBlock.endCodeAddress;
1985916df99999ae58f707d829792ef3997546628fdBen Gruver
1995916df99999ae58f707d829792ef3997546628fdBen Gruver            if (startAddress == currentStartAddress) {
2005916df99999ae58f707d829792ef3997546628fdBen Gruver                //|-----|
2015916df99999ae58f707d829792ef3997546628fdBen Gruver                //^------
2025916df99999ae58f707d829792ef3997546628fdBen Gruver                /*Bam. We hit the start of the range right on the head*/
2035916df99999ae58f707d829792ef3997546628fdBen Gruver                startBlock = tryBlock;
2045916df99999ae58f707d829792ef3997546628fdBen Gruver                break;
2055916df99999ae58f707d829792ef3997546628fdBen Gruver            } else if (startAddress > currentStartAddress && startAddress < currentEndAddress) {
2065916df99999ae58f707d829792ef3997546628fdBen Gruver                //|-----|
2075916df99999ae58f707d829792ef3997546628fdBen Gruver                //  ^----
2085916df99999ae58f707d829792ef3997546628fdBen Gruver                /*Almost. The start of the range being added is in the middle
2095916df99999ae58f707d829792ef3997546628fdBen Gruver                of an existing try range. We need to split the existing range
2105916df99999ae58f707d829792ef3997546628fdBen Gruver                at the start address of the range being added*/
2115916df99999ae58f707d829792ef3997546628fdBen Gruver                startBlock = tryBlock.split(startAddress);
2125916df99999ae58f707d829792ef3997546628fdBen Gruver                break;
2135916df99999ae58f707d829792ef3997546628fdBen Gruver            }else if (startAddress < currentStartAddress) {
2145916df99999ae58f707d829792ef3997546628fdBen Gruver                if (endAddress <= currentStartAddress) {
2155916df99999ae58f707d829792ef3997546628fdBen Gruver                    //      |-----|
2165916df99999ae58f707d829792ef3997546628fdBen Gruver                    //^--^
2175916df99999ae58f707d829792ef3997546628fdBen Gruver                    /*Oops, totally too far! The new range doesn't overlap any existing
2185916df99999ae58f707d829792ef3997546628fdBen Gruver                    ones, so we just add it and return*/
2191bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                    startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
2205916df99999ae58f707d829792ef3997546628fdBen Gruver                    tryBlock.prepend(startBlock);
2211bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                    return new TryBounds<EH>(startBlock, startBlock);
2225916df99999ae58f707d829792ef3997546628fdBen Gruver                } else {
2235916df99999ae58f707d829792ef3997546628fdBen Gruver                    //   |-----|
2245916df99999ae58f707d829792ef3997546628fdBen Gruver                    //^---------
2255916df99999ae58f707d829792ef3997546628fdBen Gruver                    /*Oops, too far! We've passed the start of the range being added, but
2265916df99999ae58f707d829792ef3997546628fdBen Gruver                     the new range does overlap this one. We need to add a new range just
2275916df99999ae58f707d829792ef3997546628fdBen Gruver                     before this one*/
2281bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                    startBlock = new MutableTryBlock<EH>(startAddress, currentStartAddress);
2295916df99999ae58f707d829792ef3997546628fdBen Gruver                    tryBlock.prepend(startBlock);
2305916df99999ae58f707d829792ef3997546628fdBen Gruver                    break;
2315916df99999ae58f707d829792ef3997546628fdBen Gruver                }
2325916df99999ae58f707d829792ef3997546628fdBen Gruver            }
2335916df99999ae58f707d829792ef3997546628fdBen Gruver
2345916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock = tryBlock.next;
2355916df99999ae58f707d829792ef3997546628fdBen Gruver        }
2365916df99999ae58f707d829792ef3997546628fdBen Gruver
2375916df99999ae58f707d829792ef3997546628fdBen Gruver        //|-----|
2385916df99999ae58f707d829792ef3997546628fdBen Gruver        //        ^-----
2395916df99999ae58f707d829792ef3997546628fdBen Gruver        /*Either the list of tries is blank, or all the tries in the list
2405916df99999ae58f707d829792ef3997546628fdBen Gruver        end before the range being added starts. In either case, we just need
2415916df99999ae58f707d829792ef3997546628fdBen Gruver        to add a new range at the end of the list*/
2425916df99999ae58f707d829792ef3997546628fdBen Gruver        if (startBlock == null) {
2431bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
2445916df99999ae58f707d829792ef3997546628fdBen Gruver            listEnd.prepend(startBlock);
2451bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            return new TryBounds<EH>(startBlock, startBlock);
2465916df99999ae58f707d829792ef3997546628fdBen Gruver        }
2475916df99999ae58f707d829792ef3997546628fdBen Gruver
2485916df99999ae58f707d829792ef3997546628fdBen Gruver        tryBlock = startBlock;
2495916df99999ae58f707d829792ef3997546628fdBen Gruver        while (tryBlock != listEnd) {
2505916df99999ae58f707d829792ef3997546628fdBen Gruver            int currentStartAddress = tryBlock.startCodeAddress;
2515916df99999ae58f707d829792ef3997546628fdBen Gruver            int currentEndAddress = tryBlock.endCodeAddress;
2525916df99999ae58f707d829792ef3997546628fdBen Gruver
2535916df99999ae58f707d829792ef3997546628fdBen Gruver            if (endAddress == currentEndAddress) {
2545916df99999ae58f707d829792ef3997546628fdBen Gruver                //|-----|
2555916df99999ae58f707d829792ef3997546628fdBen Gruver                //------^
2565916df99999ae58f707d829792ef3997546628fdBen Gruver                /*Bam! We hit the end right on the head... err, tail.*/
2571bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                return new TryBounds<EH>(startBlock, tryBlock);
2585916df99999ae58f707d829792ef3997546628fdBen Gruver            } else if (endAddress > currentStartAddress && endAddress < currentEndAddress) {
2595916df99999ae58f707d829792ef3997546628fdBen Gruver                //|-----|
2605916df99999ae58f707d829792ef3997546628fdBen Gruver                //--^
2615916df99999ae58f707d829792ef3997546628fdBen Gruver                /*Almost. The range being added ends in the middle of an
2625916df99999ae58f707d829792ef3997546628fdBen Gruver                existing range. We need to split the existing range
2635916df99999ae58f707d829792ef3997546628fdBen Gruver                at the end of the range being added.*/
2645916df99999ae58f707d829792ef3997546628fdBen Gruver                tryBlock.split(endAddress);
2651bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                return new TryBounds<EH>(startBlock, tryBlock);
2665916df99999ae58f707d829792ef3997546628fdBen Gruver            } else if (endAddress <= currentStartAddress) {
2675916df99999ae58f707d829792ef3997546628fdBen Gruver                //|-----|       |-----|
2685916df99999ae58f707d829792ef3997546628fdBen Gruver                //-----------^
2695916df99999ae58f707d829792ef3997546628fdBen Gruver                /*Oops, too far! The current range starts after the range being added
2705916df99999ae58f707d829792ef3997546628fdBen Gruver                ends. We need to create a new range that starts at the end of the
2715916df99999ae58f707d829792ef3997546628fdBen Gruver                previous range, and ends at the end of the range being added*/
2721bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                MutableTryBlock<EH> endBlock = new MutableTryBlock<EH>(tryBlock.prev.endCodeAddress, endAddress);
2735916df99999ae58f707d829792ef3997546628fdBen Gruver                tryBlock.prepend(endBlock);
2741bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                return new TryBounds<EH>(startBlock, endBlock);
2755916df99999ae58f707d829792ef3997546628fdBen Gruver            }
2765916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock = tryBlock.next;
2775916df99999ae58f707d829792ef3997546628fdBen Gruver        }
2785916df99999ae58f707d829792ef3997546628fdBen Gruver
2795916df99999ae58f707d829792ef3997546628fdBen Gruver        //|-----|
2805916df99999ae58f707d829792ef3997546628fdBen Gruver        //--------^
2815916df99999ae58f707d829792ef3997546628fdBen Gruver        /*The last range in the list ended before the end of the range being added.
2825916df99999ae58f707d829792ef3997546628fdBen Gruver        We need to add a new range that starts at the end of the last range in the
2835916df99999ae58f707d829792ef3997546628fdBen Gruver        list, and ends at the end of the range being added.*/
2841bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> endBlock = new MutableTryBlock<EH>(listEnd.prev.endCodeAddress, endAddress);
2855916df99999ae58f707d829792ef3997546628fdBen Gruver        listEnd.prepend(endBlock);
2861bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        return new TryBounds<EH>(startBlock, endBlock);
2875916df99999ae58f707d829792ef3997546628fdBen Gruver    }
2885916df99999ae58f707d829792ef3997546628fdBen Gruver
2891bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    public void addHandler(int startAddress, int endAddress, EH handler) {
2901bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        TryBounds<EH> bounds = getBoundingRanges(startAddress, endAddress);
2915916df99999ae58f707d829792ef3997546628fdBen Gruver
2921bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> startBlock = bounds.start;
2931bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> endBlock = bounds.end;
2945916df99999ae58f707d829792ef3997546628fdBen Gruver
2955916df99999ae58f707d829792ef3997546628fdBen Gruver        int previousEnd = startAddress;
2961bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        MutableTryBlock<EH> tryBlock = startBlock;
2975916df99999ae58f707d829792ef3997546628fdBen Gruver
2985916df99999ae58f707d829792ef3997546628fdBen Gruver        /*Now we have the start and end ranges that exactly match the start and end
2995916df99999ae58f707d829792ef3997546628fdBen Gruver        of the range being added. We need to iterate over all the ranges from the start
3005916df99999ae58f707d829792ef3997546628fdBen Gruver        to end range inclusively, and append the handler to the end of each range's handler
3015916df99999ae58f707d829792ef3997546628fdBen Gruver        list. We also need to create a new range for any "holes" in the existing ranges*/
3025916df99999ae58f707d829792ef3997546628fdBen Gruver        do
3035916df99999ae58f707d829792ef3997546628fdBen Gruver        {
3045916df99999ae58f707d829792ef3997546628fdBen Gruver            //is there a hole? If so, add a new range to fill the hole
3055916df99999ae58f707d829792ef3997546628fdBen Gruver            if (tryBlock.startCodeAddress > previousEnd) {
3061bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                MutableTryBlock<EH> newBlock = new MutableTryBlock<EH>(previousEnd, tryBlock.startCodeAddress);
3075916df99999ae58f707d829792ef3997546628fdBen Gruver                tryBlock.prepend(newBlock);
3085916df99999ae58f707d829792ef3997546628fdBen Gruver                tryBlock = newBlock;
3095916df99999ae58f707d829792ef3997546628fdBen Gruver            }
3105916df99999ae58f707d829792ef3997546628fdBen Gruver
3115916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock.addHandler(handler);
3125916df99999ae58f707d829792ef3997546628fdBen Gruver            previousEnd = tryBlock.endCodeAddress;
3135916df99999ae58f707d829792ef3997546628fdBen Gruver            tryBlock = tryBlock.next;
3145916df99999ae58f707d829792ef3997546628fdBen Gruver        } while (tryBlock.prev != endBlock);
3155916df99999ae58f707d829792ef3997546628fdBen Gruver    }
3165916df99999ae58f707d829792ef3997546628fdBen Gruver
3171bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver    public List<TryBlock<EH>> getTryBlocks() {
3181bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver        return Lists.newArrayList(new Iterator<TryBlock<EH>>() {
3198c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            // The next TryBlock to return. This has already been merged, if needed.
3201bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            @Nullable private MutableTryBlock<EH> next;
3218c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
3228c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            {
3238c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                next = listStart;
3248c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                next = readNextItem();
3258c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            }
3268c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
3278c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            /**
3288c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver             * Read the item that comes after the current value of the next field.
3298c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver             * @return The next item, or null if there is no next item
3308c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver             */
3311bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            @Nullable protected MutableTryBlock<EH> readNextItem() {
3321bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                // We can assume that next is not null, due to the way iteration happens
3331bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                MutableTryBlock<EH> ret = next.next;
3348c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
3358c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                if (ret == listEnd) {
3368c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                    return null;
3378c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                }
3388c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver
3398c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                while (ret.next != listEnd) {
3408c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                    if (ret.endCodeAddress == ret.next.startCodeAddress &&
3418c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                            ret.getExceptionHandlers().equals(ret.next.getExceptionHandlers())) {
3428c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                        ret.mergeNext();
3438c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                    } else {
3448c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                        break;
3458c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                    }
3468c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                }
3478c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                return ret;
3488c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver            }
3495916df99999ae58f707d829792ef3997546628fdBen Gruver
3505916df99999ae58f707d829792ef3997546628fdBen Gruver            @Override public boolean hasNext() {
3518c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                return next != null;
3525916df99999ae58f707d829792ef3997546628fdBen Gruver            }
3535916df99999ae58f707d829792ef3997546628fdBen Gruver
3541bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver            @Override @Nonnull public TryBlock<EH> next() {
3555916df99999ae58f707d829792ef3997546628fdBen Gruver                if (!hasNext()) {
3565916df99999ae58f707d829792ef3997546628fdBen Gruver                    throw new NoSuchElementException();
3575916df99999ae58f707d829792ef3997546628fdBen Gruver                }
3581bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                TryBlock<EH> ret = next;
3598c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                next = readNextItem();
3601bf6f2324541df184689fdb2c0d8188af5221784Ben Gruver                // ret can't be null (ret=next and hasNext returned true)
3618c3d16b7ee368c14e805077d047162f3bb434193Ben Gruver                return ret;
3625916df99999ae58f707d829792ef3997546628fdBen Gruver            }
3635916df99999ae58f707d829792ef3997546628fdBen Gruver
3645916df99999ae58f707d829792ef3997546628fdBen Gruver            @Override public void remove() {
3655916df99999ae58f707d829792ef3997546628fdBen Gruver                throw new UnsupportedOperationException();
3665916df99999ae58f707d829792ef3997546628fdBen Gruver            }
3675916df99999ae58f707d829792ef3997546628fdBen Gruver        });
3685916df99999ae58f707d829792ef3997546628fdBen Gruver    }
3695916df99999ae58f707d829792ef3997546628fdBen Gruver}
370