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