Home | History | Annotate | Download | only in code
      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      */
     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      */
     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      */
     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      */
     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      */
    102     public RegisterSpecList(int size) {
    103         super(size);
    104     }
    105 
    106     /** {@inheritDoc} */
    107     public Type getType(int n) {
    108         return get(n).getType().getType();
    109     }
    110 
    111     /** {@inheritDoc} */
    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} */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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