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.cst.Constant; 20import com.android.dx.rop.cst.CstString; 21import com.android.dx.rop.type.Type; 22import com.android.dx.rop.type.TypeBearer; 23import com.android.dx.util.ToHuman; 24import java.util.HashMap; 25 26/** 27 * Combination of a register number and a type, used as the sources and 28 * destinations of register-based operations. 29 */ 30public final class RegisterSpec 31 implements TypeBearer, ToHuman, Comparable<RegisterSpec> { 32 /** {@code non-null;} string to prefix register numbers with */ 33 public static final String PREFIX = "v"; 34 35 /** {@code non-null;} intern table for instances */ 36 private static final HashMap<Object, RegisterSpec> theInterns = 37 new HashMap<Object, RegisterSpec>(1000); 38 39 /** {@code non-null;} common comparison instance used while interning */ 40 private static final ForComparison theInterningItem = new ForComparison(); 41 42 /** {@code >= 0;} register number */ 43 private final int reg; 44 45 /** {@code non-null;} type loaded or stored */ 46 private final TypeBearer type; 47 48 /** 49 * {@code null-ok;} local variable info associated with this register, 50 * if any 51 */ 52 private final LocalItem local; 53 54 /** 55 * Intern the given triple as an instance of this class. 56 * 57 * @param reg {@code >= 0;} the register number 58 * @param type {@code non-null;} the type (or possibly actual value) which 59 * is loaded from or stored to the indicated register 60 * @param local {@code null-ok;} the associated local variable, if any 61 * @return {@code non-null;} an appropriately-constructed instance 62 */ 63 private static RegisterSpec intern(int reg, TypeBearer type, 64 LocalItem local) { 65 synchronized (theInterns) { 66 theInterningItem.set(reg, type, local); 67 RegisterSpec found = theInterns.get(theInterningItem); 68 69 if (found != null) { 70 return found; 71 } 72 73 found = theInterningItem.toRegisterSpec(); 74 theInterns.put(found, found); 75 return found; 76 } 77 } 78 79 /** 80 * Returns an instance for the given register number and type, with 81 * no variable info. This method is allowed to return shared 82 * instances (but doesn't necessarily do so). 83 * 84 * @param reg {@code >= 0;} the register number 85 * @param type {@code non-null;} the type (or possibly actual value) which 86 * is loaded from or stored to the indicated register 87 * @return {@code non-null;} an appropriately-constructed instance 88 */ 89 public static RegisterSpec make(int reg, TypeBearer type) { 90 return intern(reg, type, null); 91 } 92 93 /** 94 * Returns an instance for the given register number, type, and 95 * variable info. This method is allowed to return shared 96 * instances (but doesn't necessarily do so). 97 * 98 * @param reg {@code >= 0;} the register number 99 * @param type {@code non-null;} the type (or possibly actual value) which 100 * is loaded from or stored to the indicated register 101 * @param local {@code non-null;} the associated local variable 102 * @return {@code non-null;} an appropriately-constructed instance 103 */ 104 public static RegisterSpec make(int reg, TypeBearer type, 105 LocalItem local) { 106 if (local == null) { 107 throw new NullPointerException("local == null"); 108 } 109 110 return intern(reg, type, local); 111 } 112 113 /** 114 * Returns an instance for the given register number, type, and 115 * variable info. This method is allowed to return shared 116 * instances (but doesn't necessarily do so). 117 * 118 * @param reg {@code >= 0;} the register number 119 * @param type {@code non-null;} the type (or possibly actual value) which 120 * is loaded from or stored to the indicated register 121 * @param local {@code null-ok;} the associated variable info or null for 122 * none 123 * @return {@code non-null;} an appropriately-constructed instance 124 */ 125 public static RegisterSpec makeLocalOptional( 126 int reg, TypeBearer type, LocalItem local) { 127 128 return intern(reg, type, local); 129 } 130 131 /** 132 * Gets the string form for the given register number. 133 * 134 * @param reg {@code >= 0;} the register number 135 * @return {@code non-null;} the string form 136 */ 137 public static String regString(int reg) { 138 return PREFIX + reg; 139 } 140 141 /** 142 * Constructs an instance. This constructor is private. Use 143 * {@link #make}. 144 * 145 * @param reg {@code >= 0;} the register number 146 * @param type {@code non-null;} the type (or possibly actual value) which 147 * is loaded from or stored to the indicated register 148 * @param local {@code null-ok;} the associated local variable, if any 149 */ 150 private RegisterSpec(int reg, TypeBearer type, LocalItem local) { 151 if (reg < 0) { 152 throw new IllegalArgumentException("reg < 0"); 153 } 154 155 if (type == null) { 156 throw new NullPointerException("type == null"); 157 } 158 159 this.reg = reg; 160 this.type = type; 161 this.local = local; 162 } 163 164 /** {@inheritDoc} */ 165 @Override 166 public boolean equals(Object other) { 167 if (!(other instanceof RegisterSpec)) { 168 if (other instanceof ForComparison) { 169 ForComparison fc = (ForComparison) other; 170 return equals(fc.reg, fc.type, fc.local); 171 } 172 return false; 173 } 174 175 RegisterSpec spec = (RegisterSpec) other; 176 return equals(spec.reg, spec.type, spec.local); 177 } 178 179 /** 180 * Like {@code equals}, but only consider the simple types of the 181 * registers. That is, this compares {@code getType()} on the types 182 * to ignore whatever arbitrary extra stuff might be carried around 183 * by an outer {@link TypeBearer}. 184 * 185 * @param other {@code null-ok;} spec to compare to 186 * @return {@code true} iff {@code this} and {@code other} are equal 187 * in the stated way 188 */ 189 public boolean equalsUsingSimpleType(RegisterSpec other) { 190 if (!matchesVariable(other)) { 191 return false; 192 } 193 194 return (reg == other.reg); 195 } 196 197 /** 198 * Like {@link #equalsUsingSimpleType} but ignoring the register number. 199 * This is useful to determine if two instances refer to the "same" 200 * local variable. 201 * 202 * @param other {@code null-ok;} spec to compare to 203 * @return {@code true} iff {@code this} and {@code other} are equal 204 * in the stated way 205 */ 206 public boolean matchesVariable(RegisterSpec other) { 207 if (other == null) { 208 return false; 209 } 210 211 return type.getType().equals(other.type.getType()) 212 && ((local == other.local) 213 || ((local != null) && local.equals(other.local))); 214 } 215 216 /** 217 * Helper for {@link #equals} and {@link #ForComparison.equals}, 218 * which actually does the test. 219 * 220 * @param reg value of the instance variable, for another instance 221 * @param type value of the instance variable, for another instance 222 * @param local value of the instance variable, for another instance 223 * @return whether this instance is equal to one with the given 224 * values 225 */ 226 private boolean equals(int reg, TypeBearer type, LocalItem local) { 227 return (this.reg == reg) 228 && this.type.equals(type) 229 && ((this.local == local) 230 || ((this.local != null) && this.local.equals(local))); 231 } 232 233 /** 234 * Compares by (in priority order) register number, unwrapped type 235 * (that is types not {@link TypeBearer}s, and local info. 236 * 237 * @param other {@code non-null;} spec to compare to 238 * @return {@code -1..1;} standard result of comparison 239 */ 240 public int compareTo(RegisterSpec other) { 241 if (this.reg < other.reg) { 242 return -1; 243 } else if (this.reg > other.reg) { 244 return 1; 245 } 246 247 int compare = type.getType().compareTo(other.type.getType()); 248 249 if (compare != 0) { 250 return compare; 251 } 252 253 if (this.local == null) { 254 return (other.local == null) ? 0 : -1; 255 } else if (other.local == null) { 256 return 1; 257 } 258 259 return this.local.compareTo(other.local); 260 } 261 262 /** {@inheritDoc} */ 263 @Override 264 public int hashCode() { 265 return hashCodeOf(reg, type, local); 266 } 267 268 /** 269 * Helper for {@link #hashCode} and {@link #ForComparison.hashCode}, 270 * which actually does the calculation. 271 * 272 * @param reg value of the instance variable 273 * @param type value of the instance variable 274 * @param local value of the instance variable 275 * @return the hash code 276 */ 277 private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) { 278 int hash = (local != null) ? local.hashCode() : 0; 279 280 hash = (hash * 31 + type.hashCode()) * 31 + reg; 281 return hash; 282 } 283 284 /** {@inheritDoc} */ 285 @Override 286 public String toString() { 287 return toString0(false); 288 } 289 290 /** {@inheritDoc} */ 291 public String toHuman() { 292 return toString0(true); 293 } 294 295 /** {@inheritDoc} */ 296 public Type getType() { 297 return type.getType(); 298 } 299 300 /** {@inheritDoc} */ 301 public TypeBearer getFrameType() { 302 return type.getFrameType(); 303 } 304 305 /** {@inheritDoc} */ 306 public final int getBasicType() { 307 return type.getBasicType(); 308 } 309 310 /** {@inheritDoc} */ 311 public final int getBasicFrameType() { 312 return type.getBasicFrameType(); 313 } 314 315 /** {@inheritDoc} */ 316 public final boolean isConstant() { 317 return false; 318 } 319 320 /** 321 * Gets the register number. 322 * 323 * @return {@code >= 0;} the register number 324 */ 325 public int getReg() { 326 return reg; 327 } 328 329 /** 330 * Gets the type (or actual value) which is loaded from or stored 331 * to the register associated with this instance. 332 * 333 * @return {@code non-null;} the type 334 */ 335 public TypeBearer getTypeBearer() { 336 return type; 337 } 338 339 /** 340 * Gets the variable info associated with this instance, if any. 341 * 342 * @return {@code null-ok;} the variable info, or {@code null} if this 343 * instance has none 344 */ 345 public LocalItem getLocalItem() { 346 return local; 347 } 348 349 /** 350 * Gets the next available register number after the one in this 351 * instance. This is equal to the register number plus the width 352 * (category) of the type used. Among other things, this may also 353 * be used to determine the minimum required register count 354 * implied by this instance. 355 * 356 * @return {@code >= 0;} the required registers size 357 */ 358 public int getNextReg() { 359 return reg + getCategory(); 360 } 361 362 /** 363 * Gets the category of this instance's type. This is just a convenient 364 * shorthand for {@code getType().getCategory()}. 365 * 366 * @see #isCategory1 367 * @see #isCategory2 368 * @return {@code 1..2;} the category of this instance's type 369 */ 370 public int getCategory() { 371 return type.getType().getCategory(); 372 } 373 374 /** 375 * Gets whether this instance's type is category 1. This is just a 376 * convenient shorthand for {@code getType().isCategory1()}. 377 * 378 * @see #getCategory 379 * @see #isCategory2 380 * @return whether or not this instance's type is of category 1 381 */ 382 public boolean isCategory1() { 383 return type.getType().isCategory1(); 384 } 385 386 /** 387 * Gets whether this instance's type is category 2. This is just a 388 * convenient shorthand for {@code getType().isCategory2()}. 389 * 390 * @see #getCategory 391 * @see #isCategory1 392 * @return whether or not this instance's type is of category 2 393 */ 394 public boolean isCategory2() { 395 return type.getType().isCategory2(); 396 } 397 398 /** 399 * Gets the string form for just the register number of this instance. 400 * 401 * @return {@code non-null;} the register string form 402 */ 403 public String regString() { 404 return regString(reg); 405 } 406 407 /** 408 * Returns an instance that is the intersection between this instance 409 * and the given one, if any. The intersection is defined as follows: 410 * 411 * <ul> 412 * <li>If {@code other} is {@code null}, then the result 413 * is {@code null}. 414 * <li>If the register numbers don't match, then the intersection 415 * is {@code null}. Otherwise, the register number of the 416 * intersection is the same as the one in the two instances.</li> 417 * <li>If the types returned by {@code getType()} are not 418 * {@code equals()}, then the intersection is null.</li> 419 * <li>If the type bearers returned by {@code getTypeBearer()} 420 * are {@code equals()}, then the intersection's type bearer 421 * is the one from this instance. Otherwise, the intersection's 422 * type bearer is the {@code getType()} of this instance.</li> 423 * <li>If the locals are {@code equals()}, then the local info 424 * of the intersection is the local info of this instance. Otherwise, 425 * the local info of the intersection is {@code null}.</li> 426 * </ul> 427 * 428 * @param other {@code null-ok;} instance to intersect with (or {@code null}) 429 * @param localPrimary whether local variables are primary to the 430 * intersection; if {@code true}, then the only non-null 431 * results occur when registers being intersected have equal local 432 * infos (or both have {@code null} local infos) 433 * @return {@code null-ok;} the intersection 434 */ 435 public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) { 436 if (this == other) { 437 // Easy out. 438 return this; 439 } 440 441 if ((other == null) || (reg != other.getReg())) { 442 return null; 443 } 444 445 LocalItem resultLocal = 446 ((local == null) || !local.equals(other.getLocalItem())) 447 ? null : local; 448 boolean sameName = (resultLocal == local); 449 450 if (localPrimary && !sameName) { 451 return null; 452 } 453 454 Type thisType = getType(); 455 Type otherType = other.getType(); 456 457 // Note: Types are always interned. 458 if (thisType != otherType) { 459 return null; 460 } 461 462 TypeBearer resultTypeBearer = 463 type.equals(other.getTypeBearer()) ? type : thisType; 464 465 if ((resultTypeBearer == type) && sameName) { 466 // It turns out that the intersection is "this" after all. 467 return this; 468 } 469 470 return (resultLocal == null) ? make(reg, resultTypeBearer) : 471 make(reg, resultTypeBearer, resultLocal); 472 } 473 474 /** 475 * Returns an instance that is identical to this one, except that the 476 * register number is replaced by the given one. 477 * 478 * @param newReg {@code >= 0;} the new register number 479 * @return {@code non-null;} an appropriately-constructed instance 480 */ 481 public RegisterSpec withReg(int newReg) { 482 if (reg == newReg) { 483 return this; 484 } 485 486 return makeLocalOptional(newReg, type, local); 487 } 488 489 /** 490 * Returns an instance that is identical to this one, except that 491 * the type is replaced by the given one. 492 * 493 * @param newType {@code non-null;} the new type 494 * @return {@code non-null;} an appropriately-constructed instance 495 */ 496 public RegisterSpec withType(TypeBearer newType) { 497 return makeLocalOptional(reg, newType, local); 498 } 499 500 /** 501 * Returns an instance that is identical to this one, except that the 502 * register number is offset by the given amount. 503 * 504 * @param delta the amount to offset the register number by 505 * @return {@code non-null;} an appropriately-constructed instance 506 */ 507 public RegisterSpec withOffset(int delta) { 508 if (delta == 0) { 509 return this; 510 } 511 512 return withReg(reg + delta); 513 } 514 515 /** 516 * Returns an instance that is identical to this one, except that 517 * the type bearer is replaced by the actual underlying type 518 * (thereby stripping off non-type information) with any 519 * initialization information stripped away as well. 520 * 521 * @return {@code non-null;} an appropriately-constructed instance 522 */ 523 public RegisterSpec withSimpleType() { 524 TypeBearer orig = type; 525 Type newType; 526 527 if (orig instanceof Type) { 528 newType = (Type) orig; 529 } else { 530 newType = orig.getType(); 531 } 532 533 if (newType.isUninitialized()) { 534 newType = newType.getInitializedType(); 535 } 536 537 if (newType == orig) { 538 return this; 539 } 540 541 return makeLocalOptional(reg, newType, local); 542 } 543 544 /** 545 * Returns an instance that is identical to this one except that the 546 * local variable is as specified in the parameter. 547 * 548 * @param local {@code null-ok;} the local item or null for none 549 * @return an appropriate instance 550 */ 551 public RegisterSpec withLocalItem(LocalItem local) { 552 if ((this.local== local) 553 || ((this.local != null) && this.local.equals(local))) { 554 555 return this; 556 } 557 558 return makeLocalOptional(reg, type, local); 559 } 560 561 /** 562 * @return boolean specifying if this instance is an even register or not. 563 */ 564 public boolean isEvenRegister() { 565 return ((getReg() & 1) == 0); 566 } 567 568 /** 569 * Helper for {@link #toString} and {@link #toHuman}. 570 * 571 * @param human whether to be human-oriented 572 * @return {@code non-null;} the string form 573 */ 574 private String toString0(boolean human) { 575 StringBuffer sb = new StringBuffer(40); 576 577 sb.append(regString()); 578 sb.append(":"); 579 580 if (local != null) { 581 sb.append(local.toString()); 582 } 583 584 Type justType = type.getType(); 585 sb.append(justType); 586 587 if (justType != type) { 588 sb.append("="); 589 if (human && (type instanceof CstString)) { 590 sb.append(((CstString) type).toQuoted()); 591 } else if (human && (type instanceof Constant)) { 592 sb.append(type.toHuman()); 593 } else { 594 sb.append(type); 595 } 596 } 597 598 return sb.toString(); 599 } 600 601 /** 602 * Holder of register spec data for the purposes of comparison (so that 603 * {@code RegisterSpec} itself can still keep {@code final} 604 * instance variables. 605 */ 606 private static class ForComparison { 607 /** {@code >= 0;} register number */ 608 private int reg; 609 610 /** {@code non-null;} type loaded or stored */ 611 private TypeBearer type; 612 613 /** 614 * {@code null-ok;} local variable associated with this 615 * register, if any 616 */ 617 private LocalItem local; 618 619 /** 620 * Set all the instance variables. 621 * 622 * @param reg {@code >= 0;} the register number 623 * @param type {@code non-null;} the type (or possibly actual 624 * value) which is loaded from or stored to the indicated 625 * register 626 * @param local {@code null-ok;} the associated local variable, if any 627 * @return {@code non-null;} an appropriately-constructed instance 628 */ 629 public void set(int reg, TypeBearer type, LocalItem local) { 630 this.reg = reg; 631 this.type = type; 632 this.local = local; 633 } 634 635 /** 636 * Construct a {@code RegisterSpec} of this instance's 637 * contents. 638 * 639 * @return {@code non-null;} an appropriately-constructed instance 640 */ 641 public RegisterSpec toRegisterSpec() { 642 return new RegisterSpec(reg, type, local); 643 } 644 645 /** {@inheritDoc} */ 646 @Override 647 public boolean equals(Object other) { 648 if (!(other instanceof RegisterSpec)) { 649 return false; 650 } 651 652 RegisterSpec spec = (RegisterSpec) other; 653 return spec.equals(reg, type, local); 654 } 655 656 /** {@inheritDoc} */ 657 @Override 658 public int hashCode() { 659 return hashCodeOf(reg, type, local); 660 } 661 } 662} 663