1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.dex.code; 18 19 import com.android.dx.rop.cst.CstType; 20 import com.android.dx.util.FixedSizeList; 21 import com.android.dx.util.Hex; 22 23 /** 24 * Ordered list of (exception type, handler address) entries. 25 */ 26 public final class CatchHandlerList extends FixedSizeList 27 implements Comparable<CatchHandlerList> { 28 /** {@code non-null;} empty instance */ 29 public static final CatchHandlerList EMPTY = new CatchHandlerList(0); 30 31 /** 32 * Constructs an instance. All indices initially contain {@code null}. 33 * 34 * @param size {@code >= 0;} the size of the list 35 */ CatchHandlerList(int size)36 public CatchHandlerList(int size) { 37 super(size); 38 } 39 40 /** 41 * Gets the element at the given index. It is an error to call 42 * this with the index for an element which was never set; if you 43 * do that, this will throw {@code NullPointerException}. 44 * 45 * @param n {@code >= 0, < size();} which index 46 * @return {@code non-null;} element at that index 47 */ get(int n)48 public Entry get(int n) { 49 return (Entry) get0(n); 50 } 51 52 /** {@inheritDoc} */ toHuman()53 public String toHuman() { 54 return toHuman("", ""); 55 } 56 57 /** 58 * Get the human form of this instance, prefixed on each line 59 * with the string. 60 * 61 * @param prefix {@code non-null;} the prefix for every line 62 * @param header {@code non-null;} the header for the first line (after the 63 * first prefix) 64 * @return {@code non-null;} the human form 65 */ toHuman(String prefix, String header)66 public String toHuman(String prefix, String header) { 67 StringBuilder sb = new StringBuilder(100); 68 int size = size(); 69 70 sb.append(prefix); 71 sb.append(header); 72 sb.append("catch "); 73 74 for (int i = 0; i < size; i++) { 75 Entry entry = get(i); 76 77 if (i != 0) { 78 sb.append(",\n"); 79 sb.append(prefix); 80 sb.append(" "); 81 } 82 83 if ((i == (size - 1)) && catchesAll()) { 84 sb.append("<any>"); 85 } else { 86 sb.append(entry.getExceptionType().toHuman()); 87 } 88 89 sb.append(" -> "); 90 sb.append(Hex.u2or4(entry.getHandler())); 91 } 92 93 return sb.toString(); 94 } 95 96 /** 97 * Returns whether or not this instance ends with a "catch-all" 98 * handler. 99 * 100 * @return {@code true} if this instance ends with a "catch-all" 101 * handler or {@code false} if not 102 */ catchesAll()103 public boolean catchesAll() { 104 int size = size(); 105 106 if (size == 0) { 107 return false; 108 } 109 110 Entry last = get(size - 1); 111 return last.getExceptionType().equals(CstType.OBJECT); 112 } 113 114 /** 115 * Sets the entry at the given index. 116 * 117 * @param n {@code >= 0, < size();} which index 118 * @param exceptionType {@code non-null;} type of exception handled 119 * @param handler {@code >= 0;} exception handler address 120 */ set(int n, CstType exceptionType, int handler)121 public void set(int n, CstType exceptionType, int handler) { 122 set0(n, new Entry(exceptionType, handler)); 123 } 124 125 /** 126 * Sets the entry at the given index. 127 * 128 * @param n {@code >= 0, < size();} which index 129 * @param entry {@code non-null;} the entry to set at {@code n} 130 */ set(int n, Entry entry)131 public void set(int n, Entry entry) { 132 set0(n, entry); 133 } 134 135 /** {@inheritDoc} */ compareTo(CatchHandlerList other)136 public int compareTo(CatchHandlerList other) { 137 if (this == other) { 138 // Easy out. 139 return 0; 140 } 141 142 int thisSize = size(); 143 int otherSize = other.size(); 144 int checkSize = Math.min(thisSize, otherSize); 145 146 for (int i = 0; i < checkSize; i++) { 147 Entry thisEntry = get(i); 148 Entry otherEntry = other.get(i); 149 int compare = thisEntry.compareTo(otherEntry); 150 if (compare != 0) { 151 return compare; 152 } 153 } 154 155 if (thisSize < otherSize) { 156 return -1; 157 } else if (thisSize > otherSize) { 158 return 1; 159 } 160 161 return 0; 162 } 163 164 /** 165 * Entry in the list. 166 */ 167 public static class Entry implements Comparable<Entry> { 168 /** {@code non-null;} type of exception handled */ 169 private final CstType exceptionType; 170 171 /** {@code >= 0;} exception handler address */ 172 private final int handler; 173 174 /** 175 * Constructs an instance. 176 * 177 * @param exceptionType {@code non-null;} type of exception handled 178 * @param handler {@code >= 0;} exception handler address 179 */ Entry(CstType exceptionType, int handler)180 public Entry(CstType exceptionType, int handler) { 181 if (handler < 0) { 182 throw new IllegalArgumentException("handler < 0"); 183 } 184 185 if (exceptionType == null) { 186 throw new NullPointerException("exceptionType == null"); 187 } 188 189 this.handler = handler; 190 this.exceptionType = exceptionType; 191 } 192 193 /** {@inheritDoc} */ 194 @Override hashCode()195 public int hashCode() { 196 return (handler * 31) + exceptionType.hashCode(); 197 } 198 199 /** {@inheritDoc} */ 200 @Override equals(Object other)201 public boolean equals(Object other) { 202 if (other instanceof Entry) { 203 return (compareTo((Entry) other) == 0); 204 } 205 206 return false; 207 } 208 209 /** {@inheritDoc} */ compareTo(Entry other)210 public int compareTo(Entry other) { 211 if (handler < other.handler) { 212 return -1; 213 } else if (handler > other.handler) { 214 return 1; 215 } 216 217 return exceptionType.compareTo(other.exceptionType); 218 } 219 220 /** 221 * Gets the exception type handled. 222 * 223 * @return {@code non-null;} the exception type 224 */ getExceptionType()225 public CstType getExceptionType() { 226 return exceptionType; 227 } 228 229 /** 230 * Gets the handler address. 231 * 232 * @return {@code >= 0;} the handler address 233 */ getHandler()234 public int getHandler() { 235 return handler; 236 } 237 } 238 } 239