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