1 /*
2  * Copyright (C) 2007 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.rop.code;
18 
19 import com.android.dexgen.rop.type.Type;
20 import com.android.dexgen.rop.type.TypeList;
21 import com.android.dexgen.util.FixedSizeList;
22 
23 /**
24  * List of {@link RegisterSpec} instances.
25  */
26 public final class RegisterSpecList
27         extends FixedSizeList implements TypeList {
28     /** {@code non-null;} no-element instance */
29     public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
30 
31     /**
32      * Makes a single-element instance.
33      *
34      * @param spec {@code non-null;} the element
35      * @return {@code non-null;} an appropriately-constructed instance
36      */
make(RegisterSpec spec)37     public static RegisterSpecList make(RegisterSpec spec) {
38         RegisterSpecList result = new RegisterSpecList(1);
39         result.set(0, spec);
40         return result;
41     }
42 
43     /**
44      * Makes a two-element instance.
45      *
46      * @param spec0 {@code non-null;} the first element
47      * @param spec1 {@code non-null;} the second element
48      * @return {@code non-null;} an appropriately-constructed instance
49      */
make(RegisterSpec spec0, RegisterSpec spec1)50     public static RegisterSpecList make(RegisterSpec spec0,
51                                         RegisterSpec spec1) {
52         RegisterSpecList result = new RegisterSpecList(2);
53         result.set(0, spec0);
54         result.set(1, spec1);
55         return result;
56     }
57 
58     /**
59      * Makes a three-element instance.
60      *
61      * @param spec0 {@code non-null;} the first element
62      * @param spec1 {@code non-null;} the second element
63      * @param spec2 {@code non-null;} the third element
64      * @return {@code non-null;} an appropriately-constructed instance
65      */
make(RegisterSpec spec0, RegisterSpec spec1, RegisterSpec spec2)66     public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
67                                         RegisterSpec spec2) {
68         RegisterSpecList result = new RegisterSpecList(3);
69         result.set(0, spec0);
70         result.set(1, spec1);
71         result.set(2, spec2);
72         return result;
73     }
74 
75     /**
76      * Makes a four-element instance.
77      *
78      * @param spec0 {@code non-null;} the first element
79      * @param spec1 {@code non-null;} the second element
80      * @param spec2 {@code non-null;} the third element
81      * @param spec3 {@code non-null;} the fourth element
82      * @return {@code non-null;} an appropriately-constructed instance
83      */
make(RegisterSpec spec0, RegisterSpec spec1, RegisterSpec spec2, RegisterSpec spec3)84     public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
85                                         RegisterSpec spec2,
86                                         RegisterSpec spec3) {
87         RegisterSpecList result = new RegisterSpecList(4);
88         result.set(0, spec0);
89         result.set(1, spec1);
90         result.set(2, spec2);
91         result.set(3, spec3);
92         return result;
93     }
94 
95     /**
96      * Constructs an instance. All indices initially contain {@code null}.
97      *
98      * @param size the size of the list
99      */
RegisterSpecList(int size)100     public RegisterSpecList(int size) {
101         super(size);
102     }
103 
104     /** {@inheritDoc} */
getType(int n)105     public Type getType(int n) {
106         return get(n).getType().getType();
107     }
108 
109     /** {@inheritDoc} */
getWordCount()110     public int getWordCount() {
111         int sz = size();
112         int result = 0;
113 
114         for (int i = 0; i < sz; i++) {
115             result += getType(i).getCategory();
116         }
117 
118         return result;
119     }
120 
121     /** {@inheritDoc} */
withAddedType(Type type)122     public TypeList withAddedType(Type type) {
123         throw new UnsupportedOperationException("unsupported");
124     }
125 
126     /**
127      * Gets the indicated element. It is an error to call this with the
128      * index for an element which was never set; if you do that, this
129      * will throw {@code NullPointerException}.
130      *
131      * @param n {@code >= 0, < size();} which element
132      * @return {@code non-null;} the indicated element
133      */
get(int n)134     public RegisterSpec get(int n) {
135         return (RegisterSpec) get0(n);
136     }
137 
138     /**
139      * Returns a RegisterSpec in this list that uses the specified register,
140      * or null if there is none in this list.
141      * @param reg Register to find
142      * @return RegisterSpec that uses argument or null.
143      */
specForRegister(int reg)144     public RegisterSpec specForRegister(int reg) {
145         int sz = size();
146         for (int i = 0; i < sz; i++) {
147             RegisterSpec rs;
148 
149             rs = get(i);
150 
151             if (rs.getReg() == reg) {
152                 return rs;
153             }
154         }
155 
156         return null;
157     }
158 
159     /**
160      * Returns the index of a RegisterSpec in this list that uses the specified
161      * register, or -1 if none in this list uses the register.
162      * @param reg Register to find
163      * @return index of RegisterSpec or -1
164      */
indexOfRegister(int reg)165     public int indexOfRegister(int reg) {
166         int sz = size();
167         for (int i = 0; i < sz; i++) {
168             RegisterSpec rs;
169 
170             rs = get(i);
171 
172             if (rs.getReg() == reg) {
173                 return i;
174             }
175         }
176 
177         return -1;
178     }
179 
180     /**
181      * Sets the element at the given index.
182      *
183      * @param n {@code >= 0, < size();} which element
184      * @param spec {@code non-null;} the value to store
185      */
set(int n, RegisterSpec spec)186     public void set(int n, RegisterSpec spec) {
187         set0(n, spec);
188     }
189 
190     /**
191      * Gets the minimum required register count implied by this
192      * instance. This is equal to the highest register number referred
193      * to plus the widest width (largest category) of the type used in
194      * that register.
195      *
196      * @return {@code >= 0;} the required registers size
197      */
getRegistersSize()198     public int getRegistersSize() {
199         int sz = size();
200         int result = 0;
201 
202         for (int i = 0; i < sz; i++) {
203             RegisterSpec spec = (RegisterSpec) get0(i);
204             if (spec != null) {
205                 int min = spec.getNextReg();
206                 if (min > result) {
207                     result = min;
208                 }
209             }
210         }
211 
212         return result;
213     }
214 
215     /**
216      * Returns a new instance, which is the same as this instance,
217      * except that it has an additional element prepended to the original.
218      * Mutability of the result is inherited from the original.
219      *
220      * @param spec {@code non-null;} the new first spec (to prepend)
221      * @return {@code non-null;} an appropriately-constructed instance
222      */
withFirst(RegisterSpec spec)223     public RegisterSpecList withFirst(RegisterSpec spec) {
224         int sz = size();
225         RegisterSpecList result = new RegisterSpecList(sz + 1);
226 
227         for (int i = 0; i < sz; i++) {
228             result.set0(i + 1, get0(i));
229         }
230 
231         result.set0(0, spec);
232         if (isImmutable()) {
233             result.setImmutable();
234         }
235 
236         return result;
237     }
238 
239     /**
240      * Returns a new instance, which is the same as this instance,
241      * except that its first element is removed. Mutability of the
242      * result is inherited from the original.
243      *
244      * @return {@code non-null;} an appropriately-constructed instance
245      */
withoutFirst()246     public RegisterSpecList withoutFirst() {
247         int newSize = size() - 1;
248 
249         if (newSize == 0) {
250             return EMPTY;
251         }
252 
253         RegisterSpecList result = new RegisterSpecList(newSize);
254 
255         for (int i = 0; i < newSize; i++) {
256             result.set0(i, get0(i + 1));
257         }
258 
259         if (isImmutable()) {
260             result.setImmutable();
261         }
262 
263         return result;
264     }
265 
266     /**
267      * Returns a new instance, which is the same as this instance,
268      * except that its last element is removed. Mutability of the
269      * result is inherited from the original.
270      *
271      * @return {@code non-null;} an appropriately-constructed instance
272      */
withoutLast()273     public RegisterSpecList withoutLast() {
274         int newSize = size() - 1;
275 
276         if (newSize == 0) {
277             return EMPTY;
278         }
279 
280         RegisterSpecList result = new RegisterSpecList(newSize);
281 
282         for (int i = 0; i < newSize; i++) {
283             result.set0(i, get0(i));
284         }
285 
286         if (isImmutable()) {
287             result.setImmutable();
288         }
289 
290         return result;
291     }
292 
293     /**
294      * Returns an instance that is identical to this one, except that
295      * all register numbers are offset by the given amount. Mutability
296      * of the result is inherited from the original.
297      *
298      * @param delta the amount to offset the register numbers by
299      * @return {@code non-null;} an appropriately-constructed instance
300      */
withOffset(int delta)301     public RegisterSpecList withOffset(int delta) {
302         int sz = size();
303 
304         if (sz == 0) {
305             // Don't bother making a new zero-element instance.
306             return this;
307         }
308 
309         RegisterSpecList result = new RegisterSpecList(sz);
310 
311         for (int i = 0; i < sz; i++) {
312             RegisterSpec one = (RegisterSpec) get0(i);
313             if (one != null) {
314                 result.set0(i, one.withOffset(delta));
315             }
316         }
317 
318         if (isImmutable()) {
319             result.setImmutable();
320         }
321 
322         return result;
323     }
324 
325     /**
326      * Returns an instance that is identical to this one, except that
327      * all register numbers are renumbered sequentially from the given
328      * base, with the first number duplicated if indicated.
329      *
330      * @param base the base register number
331      * @param duplicateFirst whether to duplicate the first number
332      * @return {@code non-null;} an appropriately-constructed instance
333      */
withSequentialRegisters(int base, boolean duplicateFirst)334     public RegisterSpecList withSequentialRegisters(int base,
335                                                     boolean duplicateFirst) {
336         int sz = size();
337 
338         if (sz == 0) {
339             // Don't bother making a new zero-element instance.
340             return this;
341         }
342 
343         RegisterSpecList result = new RegisterSpecList(sz);
344 
345         for (int i = 0; i < sz; i++) {
346             RegisterSpec one = (RegisterSpec) get0(i);
347             result.set0(i, one.withReg(base));
348             if (duplicateFirst) {
349                 duplicateFirst = false;
350             } else {
351                 base += one.getCategory();
352             }
353         }
354 
355         if (isImmutable()) {
356             result.setImmutable();
357         }
358 
359         return result;
360     }
361 
362 }
363