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