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