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