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