1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2008 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.CatchHandlerList;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.CatchTable;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvCode;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ByteArrayAnnotatedOutput;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.Hex;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.PrintWriter;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Map;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.TreeMap;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * List of exception handlers (tuples of covered range, catch type,
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * handler address) for a particular piece of code. Instances of this
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * class correspond to a {@code try_item[]} and a
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * {@code catch_handler_item[]}.
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class CatchStructs {
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the size of a {@code try_item}: a {@code uint}
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * and two {@code ushort}s
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} code that contains the catches */
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final DalvCode code;
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} the underlying table; set in
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #finishProcessingIfNecessary}
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private CatchTable table;
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} the encoded handler list, if calculated; set in
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #encode}
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private byte[] encodedHandlers;
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * length of the handlers header (encoded size), if known; used for
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * annotation
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int encodedHandlerHeaderSize;
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #encode}
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private TreeMap<CatchHandlerList, Integer> handlerOffsets;
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance.
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param code {@code non-null;} code that contains the catches
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public CatchStructs(DalvCode code) {
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.code = code;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.table = null;
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.encodedHandlers = null;
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.encodedHandlerHeaderSize = 0;
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.handlerOffsets = null;
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Finish processing the catches, if necessary.
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void finishProcessingIfNecessary() {
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (table == null) {
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            table = code.getCatches();
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the size of the tries list, in entries.
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the tries list size
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int triesSize() {
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        finishProcessingIfNecessary();
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return table.size();
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Does a human-friendly dump of this instance.
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to dump
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix to attach to each line of output
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void debugPrint(PrintWriter out, String prefix) {
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotateEntries(prefix, out, null);
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Encodes the handler lists.
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code non-null;} file this instance is part of
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void encode(DexFile file) {
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        finishProcessingIfNecessary();
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeIdsSection typeIds = file.getTypeIds();
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int size = table.size();
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * First add a map entry for each unique list. The tree structure
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * will ensure they are sorted when we reiterate later.
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < size; i++) {
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            handlerOffsets.put(table.get(i).getHandlers(), null);
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (handlerOffsets.size() > 65535) {
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new UnsupportedOperationException(
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "too many catch handlers");
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Write out the handlers "header" consisting of its size in entries.
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encodedHandlerHeaderSize =
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.writeUleb128(handlerOffsets.size());
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Now write the lists out in order, noting the offset of each.
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Map.Entry<CatchHandlerList, Integer> mapping :
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 handlerOffsets.entrySet()) {
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CatchHandlerList list = mapping.getKey();
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int listSize = list.size();
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean catchesAll = list.catchesAll();
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Set the offset before we do any writing.
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            mapping.setValue(out.getCursor());
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (catchesAll) {
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // A size <= 0 means that the list ends with a catch-all.
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeSleb128(-(listSize - 1));
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                listSize--;
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeSleb128(listSize);
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < listSize; i++) {
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                CatchHandlerList.Entry entry = list.get(i);
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeUleb128(
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        typeIds.indexOf(entry.getExceptionType()));
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeUleb128(entry.getHandler());
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (catchesAll) {
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                out.writeUleb128(list.get(listSize).getHandler());
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encodedHandlers = out.toByteArray();
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the write size of this instance, in bytes.
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the write size
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int writeSize() {
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (triesSize() * TRY_ITEM_WRITE_SIZE) +
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                + encodedHandlers.length;
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Writes this instance to the given stream.
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code non-null;} file this instance is part of
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to write to
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void writeTo(DexFile file, AnnotatedOutput out) {
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        finishProcessingIfNecessary();
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (out.annotates()) {
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            annotateEntries("  ", null, out);
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int tableSize = table.size();
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < tableSize; i++) {
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CatchTable.Entry one = table.get(i);
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int start = one.getStart();
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int end = one.getEnd();
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int insnCount = end - start;
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (insnCount >= 65536) {
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new UnsupportedOperationException(
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        "bogus exception range: " + Hex.u4(start) + ".." +
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        Hex.u4(end));
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.writeInt(start);
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.writeShort(insnCount);
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.writeShort(handlerOffsets.get(one.getHandlers()));
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        out.write(encodedHandlers);
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper method to annotate or simply print the exception handlers.
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Only one of {@code printTo} or {@code annotateTo} should
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * be non-null.
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix for each line
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param printTo {@code null-ok;} where to print to
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void annotateEntries(String prefix, PrintWriter printTo,
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            AnnotatedOutput annotateTo) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        finishProcessingIfNecessary();
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean consume = (annotateTo != null);
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int amt1 = consume ? 6 : 0;
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int amt2 = consume ? 2 : 0;
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int size = table.size();
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String subPrefix = prefix + "  ";
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (consume) {
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            annotateTo.annotate(0, prefix + "tries:");
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            printTo.println(prefix + "tries:");
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < size; i++) {
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CatchTable.Entry entry = table.get(i);
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CatchHandlerList handlers = entry.getHandlers();
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart())
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                + ".." + Hex.u2or4(entry.getEnd());
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            String s2 = handlers.toHuman(subPrefix, "");
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (consume) {
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                annotateTo.annotate(amt1, s1);
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                annotateTo.annotate(amt2, s2);
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                printTo.println(s1);
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                printTo.println(s2);
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (! consume) {
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Only emit the handler lists if we are consuming bytes.
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return;
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotateTo.annotate(0, prefix + "handlers:");
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotateTo.annotate(encodedHandlerHeaderSize,
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int lastOffset = 0;
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        CatchHandlerList lastList = null;
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Map.Entry<CatchHandlerList, Integer> mapping :
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 handlerOffsets.entrySet()) {
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CatchHandlerList list = mapping.getKey();
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int offset = mapping.getValue();
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (lastList != null) {
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                annotateAndConsumeHandlers(lastList, lastOffset,
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        offset - lastOffset, subPrefix, printTo, annotateTo);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            lastList = list;
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            lastOffset = offset;
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotateAndConsumeHandlers(lastList, lastOffset,
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                encodedHandlers.length - lastOffset,
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                subPrefix, printTo, annotateTo);
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #annotateEntries} to annotate a catch handler list
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * while consuming it.
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param handlers {@code non-null;} handlers to annotate
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param offset {@code >= 0;} the offset of this handler
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param size {@code >= 1;} the number of bytes the handlers consume
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix for each line
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param printTo {@code null-ok;} where to print to
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param annotateTo {@code non-null;} where to annotate to
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void annotateAndConsumeHandlers(CatchHandlerList handlers,
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int offset, int size, String prefix, PrintWriter printTo,
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            AnnotatedOutput annotateTo) {
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (printTo != null) {
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            printTo.println(s);
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        annotateTo.annotate(size, s);
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
316