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