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