1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2008 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.file;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.CatchHandlerList;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.CatchTable;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.DalvCode;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.AnnotatedOutput;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ByteArrayAnnotatedOutput;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Hex;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.PrintWriter;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Map;
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.TreeMap;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * List of exception handlers (tuples of covered range, catch type,
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * handler address) for a particular piece of code. Instances of this
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * class correspond to a {@code try_item[]} and a
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code catch_handler_item[]}.
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class CatchStructs {
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the size of a {@code try_item}: a {@code uint}
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * and two {@code ushort}s
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} code that contains the catches */
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final DalvCode code;
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code null-ok;} the underlying table; set in
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link #finishProcessingIfNecessary}
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private CatchTable table;
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code null-ok;} the encoded handler list, if calculated; set in
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link #encode}
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private byte[] encodedHandlers;
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * length of the handlers header (encoded size), if known; used for
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * annotation
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int encodedHandlerHeaderSize;
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link #encode}
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private TreeMap<CatchHandlerList, Integer> handlerOffsets;
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance.
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param code {@code non-null;} code that contains the catches
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public CatchStructs(DalvCode code) {
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.code = code;
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.table = null;
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.encodedHandlers = null;
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.encodedHandlerHeaderSize = 0;
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.handlerOffsets = null;
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Finish processing the catches, if necessary.
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void finishProcessingIfNecessary() {
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (table == null) {
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            table = code.getCatches();
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the size of the tries list, in entries.
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code >= 0;} the tries list size
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int triesSize() {
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        finishProcessingIfNecessary();
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return table.size();
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Does a human-friendly dump of this instance.
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to dump
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param prefix {@code non-null;} prefix to attach to each line of output
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void debugPrint(PrintWriter out, String prefix) {
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateEntries(prefix, out, null);
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Encodes the handler lists.
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file this instance is part of
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void encode(DexFile file) {
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        finishProcessingIfNecessary();
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        TypeIdsSection typeIds = file.getTypeIds();
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = table.size();
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        handlerOffsets = new TreeMap<CatchHandlerList, Integer>();
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * First add a map entry for each unique list. The tree structure
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * will ensure they are sorted when we reiterate later.
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            handlerOffsets.put(table.get(i).getHandlers(), null);
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (handlerOffsets.size() > 65535) {
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new UnsupportedOperationException(
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "too many catch handlers");
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Write out the handlers "header" consisting of its size in entries.
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodedHandlerHeaderSize =
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeUnsignedLeb128(handlerOffsets.size());
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Now write the lists out in order, noting the offset of each.
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (Map.Entry<CatchHandlerList, Integer> mapping :
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 handlerOffsets.entrySet()) {
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CatchHandlerList list = mapping.getKey();
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int listSize = list.size();
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean catchesAll = list.catchesAll();
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Set the offset before we do any writing.
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            mapping.setValue(out.getCursor());
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (catchesAll) {
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // A size <= 0 means that the list ends with a catch-all.
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeSignedLeb128(-(listSize - 1));
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                listSize--;
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeSignedLeb128(listSize);
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < listSize; i++) {
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                CatchHandlerList.Entry entry = list.get(i);
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeUnsignedLeb128(
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        typeIds.indexOf(entry.getExceptionType()));
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeUnsignedLeb128(entry.getHandler());
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (catchesAll) {
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeUnsignedLeb128(list.get(listSize).getHandler());
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodedHandlers = out.toByteArray();
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the write size of this instance, in bytes.
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code >= 0;} the write size
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int writeSize() {
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (triesSize() * TRY_ITEM_WRITE_SIZE) +
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                + encodedHandlers.length;
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Writes this instance to the given stream.
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file this instance is part of
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to write to
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void writeTo(DexFile file, AnnotatedOutput out) {
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        finishProcessingIfNecessary();
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (out.annotates()) {
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotateEntries("  ", null, out);
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int tableSize = table.size();
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < tableSize; i++) {
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CatchTable.Entry one = table.get(i);
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int start = one.getStart();
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int end = one.getEnd();
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int insnCount = end - start;
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (insnCount >= 65536) {
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new UnsupportedOperationException(
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        "bogus exception range: " + Hex.u4(start) + ".." +
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        Hex.u4(end));
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeInt(start);
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(insnCount);
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(handlerOffsets.get(one.getHandlers()));
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        out.write(encodedHandlers);
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper method to annotate or simply print the exception handlers.
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Only one of {@code printTo} or {@code annotateTo} should
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * be non-null.
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param prefix {@code non-null;} prefix for each line
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param printTo {@code null-ok;} where to print to
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param annotateTo {@code null-ok;} where to consume bytes and annotate to
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void annotateEntries(String prefix, PrintWriter printTo,
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            AnnotatedOutput annotateTo) {
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        finishProcessingIfNecessary();
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean consume = (annotateTo != null);
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int amt1 = consume ? 6 : 0;
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int amt2 = consume ? 2 : 0;
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = table.size();
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        String subPrefix = prefix + "  ";
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (consume) {
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotateTo.annotate(0, prefix + "tries:");
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            printTo.println(prefix + "tries:");
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CatchTable.Entry entry = table.get(i);
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CatchHandlerList handlers = entry.getHandlers();
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart())
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                + ".." + Hex.u2or4(entry.getEnd());
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            String s2 = handlers.toHuman(subPrefix, "");
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (consume) {
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                annotateTo.annotate(amt1, s1);
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                annotateTo.annotate(amt2, s2);
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                printTo.println(s1);
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                printTo.println(s2);
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (! consume) {
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Only emit the handler lists if we are consuming bytes.
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return;
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateTo.annotate(0, prefix + "handlers:");
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateTo.annotate(encodedHandlerHeaderSize,
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                subPrefix + "size: " + Hex.u2(handlerOffsets.size()));
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int lastOffset = 0;
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CatchHandlerList lastList = null;
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (Map.Entry<CatchHandlerList, Integer> mapping :
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 handlerOffsets.entrySet()) {
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CatchHandlerList list = mapping.getKey();
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int offset = mapping.getValue();
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (lastList != null) {
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                annotateAndConsumeHandlers(lastList, lastOffset,
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        offset - lastOffset, subPrefix, printTo, annotateTo);
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastList = list;
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastOffset = offset;
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateAndConsumeHandlers(lastList, lastOffset,
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                encodedHandlers.length - lastOffset,
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                subPrefix, printTo, annotateTo);
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #annotateEntries} to annotate a catch handler list
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * while consuming it.
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param handlers {@code non-null;} handlers to annotate
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param offset {@code >= 0;} the offset of this handler
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param size {@code >= 1;} the number of bytes the handlers consume
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param prefix {@code non-null;} prefix for each line
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param printTo {@code null-ok;} where to print to
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param annotateTo {@code non-null;} where to annotate to
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void annotateAndConsumeHandlers(CatchHandlerList handlers,
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int offset, int size, String prefix, PrintWriter printTo,
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            AnnotatedOutput annotateTo) {
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        String s = handlers.toHuman(prefix, Hex.u2(offset) + ": ");
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (printTo != null) {
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            printTo.println(s);
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateTo.annotate(size, s);
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
318