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