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.dexgen.dex.code;
18 
19 import com.android.dexgen.rop.cst.CstType;
20 import com.android.dexgen.util.FixedSizeList;
21 
22 /**
23  * Table of catch entries. Each entry includes a range of code
24  * addresses for which it is valid and an associated {@link
25  * CatchHandlerList}.
26  */
27 public final class CatchTable extends FixedSizeList
28         implements Comparable<CatchTable> {
29     /** {@code non-null;} empty instance */
30     public static final CatchTable EMPTY = new CatchTable(0);
31 
32     /**
33      * Constructs an instance. All indices initially contain {@code null}.
34      *
35      * @param size {@code >= 0;} the size of the table
36      */
CatchTable(int size)37     public CatchTable(int size) {
38         super(size);
39     }
40 
41     /**
42      * Gets the element at the given index. It is an error to call
43      * this with the index for an element which was never set; if you
44      * do that, this will throw {@code NullPointerException}.
45      *
46      * @param n {@code >= 0, < size();} which index
47      * @return {@code non-null;} element at that index
48      */
get(int n)49     public Entry get(int n) {
50         return (Entry) get0(n);
51     }
52 
53     /**
54      * Sets the entry at the given index.
55      *
56      * @param n {@code >= 0, < size();} which index
57      * @param entry {@code non-null;} the entry to set at {@code n}
58      */
set(int n, Entry entry)59     public void set(int n, Entry entry) {
60         set0(n, entry);
61     }
62 
63     /** {@inheritDoc} */
compareTo(CatchTable other)64     public int compareTo(CatchTable other) {
65         if (this == other) {
66             // Easy out.
67             return 0;
68         }
69 
70         int thisSize = size();
71         int otherSize = other.size();
72         int checkSize = Math.min(thisSize, otherSize);
73 
74         for (int i = 0; i < checkSize; i++) {
75             Entry thisEntry = get(i);
76             Entry otherEntry = other.get(i);
77             int compare = thisEntry.compareTo(otherEntry);
78             if (compare != 0) {
79                 return compare;
80             }
81         }
82 
83         if (thisSize < otherSize) {
84             return -1;
85         } else if (thisSize > otherSize) {
86             return 1;
87         }
88 
89         return 0;
90     }
91 
92     /**
93      * Entry in a catch list.
94      */
95     public static class Entry implements Comparable<Entry> {
96         /** {@code >= 0;} start address */
97         private final int start;
98 
99         /** {@code > start;} end address (exclusive) */
100         private final int end;
101 
102         /** {@code non-null;} list of catch handlers */
103         private final CatchHandlerList handlers;
104 
105         /**
106          * Constructs an instance.
107          *
108          * @param start {@code >= 0;} start address
109          * @param end {@code > start;} end address (exclusive)
110          * @param handlers {@code non-null;} list of catch handlers
111          */
Entry(int start, int end, CatchHandlerList handlers)112         public Entry(int start, int end, CatchHandlerList handlers) {
113             if (start < 0) {
114                 throw new IllegalArgumentException("start < 0");
115             }
116 
117             if (end <= start) {
118                 throw new IllegalArgumentException("end <= start");
119             }
120 
121             if (handlers.isMutable()) {
122                 throw new IllegalArgumentException("handlers.isMutable()");
123             }
124 
125             this.start = start;
126             this.end = end;
127             this.handlers = handlers;
128         }
129 
130         /** {@inheritDoc} */
131         @Override
hashCode()132         public int hashCode() {
133             int hash = (start * 31) + end;
134             hash = (hash * 31) + handlers.hashCode();
135             return hash;
136         }
137 
138         /** {@inheritDoc} */
139         @Override
equals(Object other)140         public boolean equals(Object other) {
141             if (other instanceof Entry) {
142                 return (compareTo((Entry) other) == 0);
143             }
144 
145             return false;
146         }
147 
148         /** {@inheritDoc} */
compareTo(Entry other)149         public int compareTo(Entry other) {
150             if (start < other.start) {
151                 return -1;
152             } else if (start > other.start) {
153                 return 1;
154             }
155 
156             if (end < other.end) {
157                 return -1;
158             } else if (end > other.end) {
159                 return 1;
160             }
161 
162             return handlers.compareTo(other.handlers);
163         }
164 
165         /**
166          * Gets the start address.
167          *
168          * @return {@code >= 0;} the start address
169          */
getStart()170         public int getStart() {
171             return start;
172         }
173 
174         /**
175          * Gets the end address (exclusive).
176          *
177          * @return {@code > start;} the end address (exclusive)
178          */
getEnd()179         public int getEnd() {
180             return end;
181         }
182 
183         /**
184          * Gets the handlers.
185          *
186          * @return {@code non-null;} the handlers
187          */
getHandlers()188         public CatchHandlerList getHandlers() {
189             return handlers;
190         }
191     }
192 }
193