1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.dexlib2.analysis; 33 34 import com.google.common.base.Objects; 35 import com.google.common.collect.Lists; 36 import com.google.common.collect.Maps; 37 import org.jf.dexlib2.Opcode; 38 import org.jf.dexlib2.iface.instruction.*; 39 import org.jf.dexlib2.iface.instruction.formats.Instruction22c; 40 import org.jf.dexlib2.iface.reference.MethodReference; 41 import org.jf.dexlib2.iface.reference.Reference; 42 import org.jf.dexlib2.iface.reference.TypeReference; 43 import org.jf.util.ExceptionWithContext; 44 45 import javax.annotation.Nonnull; 46 import javax.annotation.Nullable; 47 import java.util.*; 48 49 public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> { 50 /** 51 * The MethodAnalyzer containing this instruction 52 */ 53 @Nonnull 54 protected final MethodAnalyzer methodAnalyzer; 55 56 /** 57 * The actual instruction 58 */ 59 @Nonnull 60 protected Instruction instruction; 61 62 /** 63 * The index of the instruction, where the first instruction in the method is at index 0, and so on 64 */ 65 protected final int instructionIndex; 66 67 /** 68 * Instructions that can pass on execution to this one during normal execution 69 */ 70 @Nonnull 71 protected final TreeSet<AnalyzedInstruction> predecessors = new TreeSet<AnalyzedInstruction>(); 72 73 /** 74 * Instructions that can execution could pass on to next during normal execution 75 */ 76 @Nonnull 77 protected final LinkedList<AnalyzedInstruction> successors = new LinkedList<AnalyzedInstruction>(); 78 79 /** 80 * This contains the register types *before* the instruction has executed 81 */ 82 @Nonnull 83 protected final RegisterType[] preRegisterMap; 84 85 /** 86 * This contains the register types *after* the instruction has executed 87 */ 88 @Nonnull 89 protected final RegisterType[] postRegisterMap; 90 91 /** 92 * This contains optional register type overrides for register types from predecessors 93 */ 94 @Nullable 95 protected Map<PredecessorOverrideKey, RegisterType> predecessorRegisterOverrides = null; 96 97 /** 98 * When deodexing, we might need to deodex this instruction multiple times, when we merge in new register 99 * information. When this happens, we need to restore the original (odexed) instruction, so we can deodex it again 100 */ 101 protected final Instruction originalInstruction; 102 AnalyzedInstruction(@onnull MethodAnalyzer methodAnalyzer, @Nonnull Instruction instruction, int instructionIndex, int registerCount)103 public AnalyzedInstruction(@Nonnull MethodAnalyzer methodAnalyzer, @Nonnull Instruction instruction, 104 int instructionIndex, int registerCount) { 105 this.methodAnalyzer = methodAnalyzer; 106 this.instruction = instruction; 107 this.originalInstruction = instruction; 108 this.instructionIndex = instructionIndex; 109 this.postRegisterMap = new RegisterType[registerCount]; 110 this.preRegisterMap = new RegisterType[registerCount]; 111 RegisterType unknown = RegisterType.getRegisterType(RegisterType.UNKNOWN, null); 112 for (int i=0; i<registerCount; i++) { 113 preRegisterMap[i] = unknown; 114 postRegisterMap[i] = unknown; 115 } 116 } 117 getInstructionIndex()118 public int getInstructionIndex() { 119 return instructionIndex; 120 } 121 getPredecessorCount()122 public int getPredecessorCount() { 123 return predecessors.size(); 124 } 125 getPredecessors()126 public SortedSet<AnalyzedInstruction> getPredecessors() { 127 return Collections.unmodifiableSortedSet(predecessors); 128 } 129 getPredecessorRegisterType(@onnull AnalyzedInstruction predecessor, int registerNumber)130 public RegisterType getPredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber) { 131 if (predecessorRegisterOverrides != null) { 132 RegisterType override = predecessorRegisterOverrides.get( 133 new PredecessorOverrideKey(predecessor, registerNumber)); 134 if (override != null) { 135 return override; 136 } 137 } 138 return predecessor.postRegisterMap[registerNumber]; 139 } 140 addPredecessor(AnalyzedInstruction predecessor)141 protected boolean addPredecessor(AnalyzedInstruction predecessor) { 142 return predecessors.add(predecessor); 143 } 144 addSuccessor(AnalyzedInstruction successor)145 protected void addSuccessor(AnalyzedInstruction successor) { 146 successors.add(successor); 147 } 148 setDeodexedInstruction(Instruction instruction)149 protected void setDeodexedInstruction(Instruction instruction) { 150 assert originalInstruction.getOpcode().odexOnly(); 151 this.instruction = instruction; 152 } 153 restoreOdexedInstruction()154 protected void restoreOdexedInstruction() { 155 assert originalInstruction.getOpcode().odexOnly(); 156 instruction = originalInstruction; 157 } 158 159 @Nonnull getSuccessors()160 public List<AnalyzedInstruction> getSuccessors() { 161 return Collections.unmodifiableList(successors); 162 } 163 164 @Nonnull getInstruction()165 public Instruction getInstruction() { 166 return instruction; 167 } 168 169 @Nonnull getOriginalInstruction()170 public Instruction getOriginalInstruction() { 171 return originalInstruction; 172 } 173 174 /** 175 * Is this instruction a "beginning instruction". A beginning instruction is defined to be an instruction 176 * that can be the first successfully executed instruction in the method. The first instruction is always a 177 * beginning instruction. If the first instruction can throw an exception, and is covered by a try block, then 178 * the first instruction of any exception handler for that try block is also a beginning instruction. And likewise, 179 * if any of those instructions can throw an exception and are covered by try blocks, the first instruction of the 180 * corresponding exception handler is a beginning instruction, etc. 181 * 182 * To determine this, we simply check if the first predecessor is the fake "StartOfMethod" instruction, which has 183 * an instruction index of -1. 184 * @return a boolean value indicating whether this instruction is a beginning instruction 185 */ isBeginningInstruction()186 public boolean isBeginningInstruction() { 187 //if this instruction has no predecessors, it is either the fake "StartOfMethod" instruction or it is an 188 //unreachable instruction. 189 if (predecessors.size() == 0) { 190 return false; 191 } 192 return predecessors.first().instructionIndex == -1; 193 } 194 195 /* 196 * Merges the given register type into the specified pre-instruction register, and also sets the post-instruction 197 * register type accordingly if it isn't a destination register for this instruction 198 * @param registerNumber Which register to set 199 * @param registerType The register type 200 * @returns true If the post-instruction register type was changed. This might be false if either the specified 201 * register is a destination register for this instruction, or if the pre-instruction register type didn't change 202 * after merging in the given register type 203 */ mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions, boolean override)204 protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions, 205 boolean override) { 206 assert registerNumber >= 0 && registerNumber < postRegisterMap.length; 207 assert registerType != null; 208 209 RegisterType oldRegisterType = preRegisterMap[registerNumber]; 210 211 RegisterType mergedRegisterType; 212 if (override) { 213 mergedRegisterType = getMergedPreRegisterTypeFromPredecessors(registerNumber); 214 } else { 215 mergedRegisterType = oldRegisterType.merge(registerType); 216 } 217 218 if (mergedRegisterType.equals(oldRegisterType)) { 219 return false; 220 } 221 222 preRegisterMap[registerNumber] = mergedRegisterType; 223 verifiedInstructions.clear(instructionIndex); 224 225 if (!setsRegister(registerNumber)) { 226 postRegisterMap[registerNumber] = mergedRegisterType; 227 return true; 228 } 229 230 return false; 231 } 232 233 /** 234 * Iterates over the predecessors of this instruction, and merges all the post-instruction register types for the 235 * given register. Any dead, unreachable, or odexed predecessor is ignored. This takes into account any overridden 236 * predecessor register types 237 * 238 * @param registerNumber the register number 239 * @return The register type resulting from merging the post-instruction register types from all predecessors 240 */ 241 @Nonnull 242 protected RegisterType getMergedPreRegisterTypeFromPredecessors(int registerNumber) { 243 RegisterType mergedRegisterType = null; 244 for (AnalyzedInstruction predecessor: predecessors) { 245 RegisterType predecessorRegisterType = getPredecessorRegisterType(predecessor, registerNumber); 246 if (predecessorRegisterType != null) { 247 if (mergedRegisterType == null) { 248 mergedRegisterType = predecessorRegisterType; 249 } else { 250 mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType); 251 } 252 } 253 } 254 if (mergedRegisterType == null) { 255 // This is a start-of-method or unreachable instruction. 256 throw new IllegalStateException(); 257 } 258 return mergedRegisterType; 259 } 260 /** 261 * Sets the "post-instruction" register type as indicated. 262 * @param registerNumber Which register to set 263 * @param registerType The "post-instruction" register type 264 * @return true if the given register type is different than the existing post-instruction register type 265 */ 266 protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) { 267 assert registerNumber >= 0 && registerNumber < postRegisterMap.length; 268 assert registerType != null; 269 270 RegisterType oldRegisterType = postRegisterMap[registerNumber]; 271 if (oldRegisterType.equals(registerType)) { 272 return false; 273 } 274 275 postRegisterMap[registerNumber] = registerType; 276 return true; 277 } 278 279 /** 280 * Adds an override for a register type from a predecessor. 281 * 282 * This is used to set the register type for only one branch from a conditional jump. 283 * 284 * @param predecessor Which predecessor is being overridden 285 * @param registerNumber The register number of the register being overridden 286 * @param registerType The overridden register type 287 * @param verifiedInstructions A bit vector of instructions that have been verified 288 * 289 * @return true if the post-instruction register type for this instruction changed as a result of this override 290 */ 291 protected boolean overridePredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber, 292 @Nonnull RegisterType registerType, BitSet verifiedInstructions) { 293 if (predecessorRegisterOverrides == null) { 294 predecessorRegisterOverrides = Maps.newHashMap(); 295 } 296 predecessorRegisterOverrides.put(new PredecessorOverrideKey(predecessor, registerNumber), registerType); 297 298 RegisterType mergedType = getMergedPreRegisterTypeFromPredecessors(registerNumber); 299 300 if (preRegisterMap[registerNumber].equals(mergedType)) { 301 return false; 302 } 303 304 preRegisterMap[registerNumber] = mergedType; 305 verifiedInstructions.clear(instructionIndex); 306 307 if (!setsRegister(registerNumber)) { 308 if (!postRegisterMap[registerNumber].equals(mergedType)) { 309 postRegisterMap[registerNumber] = mergedType; 310 return true; 311 } 312 } 313 314 return false; 315 } 316 317 public boolean isInvokeInit() { 318 if (!instruction.getOpcode().canInitializeReference()) { 319 return false; 320 } 321 322 ReferenceInstruction instruction = (ReferenceInstruction)this.instruction; 323 324 Reference reference = instruction.getReference(); 325 if (reference instanceof MethodReference) { 326 return ((MethodReference)reference).getName().equals("<init>"); 327 } 328 329 return false; 330 } 331 332 /** 333 * Determines if this instruction sets the given register, or alters its type 334 * 335 * @param registerNumber The register to check 336 * @return true if this instruction sets the given register or alters its type 337 */ 338 public boolean setsRegister(int registerNumber) { 339 // This method could be implemented by calling getSetRegisters and checking if registerNumber is in the result 340 // However, this is a frequently called method, and this is a more efficient implementation, because it doesn't 341 // allocate a new list, and it can potentially exit earlier 342 343 if (isInvokeInit()) { 344 // When constructing a new object, the register type will be an uninitialized reference after the 345 // new-instance instruction, but becomes an initialized reference once the <init> method is called. So even 346 // though invoke instructions don't normally change any registers, calling an <init> method will change the 347 // type of its object register. If the uninitialized reference has been copied to other registers, they will 348 // be initialized as well, so we need to check for that too 349 int destinationRegister; 350 if (instruction instanceof FiveRegisterInstruction) { 351 assert ((FiveRegisterInstruction)instruction).getRegisterCount() > 0; 352 destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterC(); 353 } else { 354 assert instruction instanceof RegisterRangeInstruction; 355 RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction; rangeInstruction.getRegisterCount()356 assert rangeInstruction.getRegisterCount() > 0; 357 destinationRegister = rangeInstruction.getStartRegister(); 358 } 359 360 RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister); 361 if (preInstructionDestRegisterType.category == RegisterType.UNKNOWN) { 362 // We never let an uninitialized reference propagate past an invoke-init if the object register type is 363 // unknown This is because the uninitialized reference may be an alias to the reference being 364 // initialized, but we can't know that until the object register's type is known 365 RegisterType preInstructionRegisterType = getPreInstructionRegisterType(registerNumber); 366 if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || 367 preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { 368 return true; 369 } 370 } 371 372 if (preInstructionDestRegisterType.category != RegisterType.UNINIT_REF && 373 preInstructionDestRegisterType.category != RegisterType.UNINIT_THIS) { 374 return false; 375 } 376 377 if (registerNumber == destinationRegister) { 378 return true; 379 } 380 381 //check if the uninit ref has been copied to another register 382 return preInstructionDestRegisterType.equals(getPreInstructionRegisterType(registerNumber)); 383 } 384 385 // On art, the optimizer will often nop out a check-cast instruction after an instance-of instruction. 386 // Normally, check-cast is where the register type actually changes. 387 // In order to correctly handle this case, we have to propagate the narrowed register type to the appropriate 388 // branch of the following if-eqz/if-nez 389 if (instructionIndex > 0 && 390 methodAnalyzer.getClassPath().isArt() && 391 getPredecessorCount() == 1 && 392 (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) { 393 394 AnalyzedInstruction prevInstruction = predecessors.first(); 395 if (prevInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && 396 MethodAnalyzer.canPropagateTypeAfterInstanceOf( 397 prevInstruction, this, methodAnalyzer.getClassPath())) { 398 Instruction22c instanceOfInstruction = (Instruction22c)prevInstruction.instruction; 399 400 if (registerNumber == instanceOfInstruction.getRegisterB()) { 401 return true; 402 } 403 404 // Additionally, there may be a move instruction just before the instance-of, in order to put the value 405 // into a register that is addressable by the instance-of. In this case, we also need to propagate the 406 // new register type for the original register that the value was moved from. 407 // In some cases, the instance-of may have multiple predecessors. In this case, we should only do the 408 // propagation if all predecessors are move-object instructions for the same source register 409 // TODO: do we need to do some sort of additional check that these multiple move-object predecessors actually refer to the same value? 410 if (instructionIndex > 1) { 411 int originalSourceRegister = -1; 412 413 RegisterType newType = null; 414 415 for (AnalyzedInstruction prevPrevAnalyzedInstruction : prevInstruction.predecessors) { 416 Opcode opcode = prevPrevAnalyzedInstruction.instruction.getOpcode(); 417 if (opcode == Opcode.MOVE_OBJECT || opcode == Opcode.MOVE_OBJECT_16 || 418 opcode == Opcode.MOVE_OBJECT_FROM16) { 419 TwoRegisterInstruction moveInstruction = 420 ((TwoRegisterInstruction)prevPrevAnalyzedInstruction.instruction); 421 RegisterType originalType = 422 prevPrevAnalyzedInstruction.getPostInstructionRegisterType( 423 moveInstruction.getRegisterB()); 424 if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) { 425 originalSourceRegister = -1; 426 break; 427 } 428 if (originalType.type == null) { 429 originalSourceRegister = -1; 430 break; 431 } 432 433 if (newType == null) { 434 newType = RegisterType.getRegisterType(methodAnalyzer.getClassPath(), 435 (TypeReference)instanceOfInstruction.getReference()); 436 } 437 438 if (MethodAnalyzer.isNotWideningConversion(originalType, newType)) { 439 if (originalSourceRegister != -1) { 440 if (originalSourceRegister != moveInstruction.getRegisterB()) { 441 originalSourceRegister = -1; 442 break; 443 } 444 } else { 445 originalSourceRegister = moveInstruction.getRegisterB(); 446 } 447 } 448 } else { 449 originalSourceRegister = -1; 450 break; 451 } 452 } 453 if (originalSourceRegister != -1 && registerNumber == originalSourceRegister) { 454 return true; 455 } 456 } 457 } 458 } 459 460 if (!instruction.getOpcode().setsRegister()) { 461 return false; 462 } 463 int destinationRegister = getDestinationRegister(); 464 465 if (registerNumber == destinationRegister) { 466 return true; 467 } 468 if (instruction.getOpcode().setsWideRegister() && registerNumber == (destinationRegister + 1)) { 469 return true; 470 } 471 return false; 472 } 473 474 public List<Integer> getSetRegisters() { 475 List<Integer> setRegisters = Lists.newArrayList(); 476 477 if (instruction.getOpcode().setsRegister()) { 478 setRegisters.add(getDestinationRegister()); 479 } 480 if (instruction.getOpcode().setsWideRegister()) { 481 setRegisters.add(getDestinationRegister() + 1); 482 } 483 484 if (isInvokeInit()) { 485 //When constructing a new object, the register type will be an uninitialized reference after the new-instance 486 //instruction, but becomes an initialized reference once the <init> method is called. So even though invoke 487 //instructions don't normally change any registers, calling an <init> method will change the type of its 488 //object register. If the uninitialized reference has been copied to other registers, they will be initialized 489 //as well, so we need to check for that too 490 491 int destinationRegister; 492 if (instruction instanceof FiveRegisterInstruction) { 493 destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterC(); 494 assert ((FiveRegisterInstruction)instruction).getRegisterCount() > 0; 495 } else { 496 assert instruction instanceof RegisterRangeInstruction; 497 RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction; 498 assert rangeInstruction.getRegisterCount() > 0; 499 destinationRegister = rangeInstruction.getStartRegister(); 500 } 501 502 RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(destinationRegister); 503 if (preInstructionDestRegisterType.category == RegisterType.UNINIT_REF || 504 preInstructionDestRegisterType.category == RegisterType.UNINIT_THIS) { 505 setRegisters.add(destinationRegister); 506 507 RegisterType objectRegisterType = preRegisterMap[destinationRegister]; 508 for (int i = 0; i < preRegisterMap.length; i++) { 509 if (i == destinationRegister) { 510 continue; 511 } 512 513 RegisterType preInstructionRegisterType = preRegisterMap[i]; 514 515 if (preInstructionRegisterType.equals(objectRegisterType)) { 516 setRegisters.add(i); 517 } else if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || 518 preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { 519 RegisterType postInstructionRegisterType = postRegisterMap[i]; 520 if (postInstructionRegisterType.category == RegisterType.UNKNOWN) { 521 setRegisters.add(i); 522 } 523 } 524 } 525 } else if (preInstructionDestRegisterType.category == RegisterType.UNKNOWN) { 526 // We never let an uninitialized reference propagate past an invoke-init if the object register type is 527 // unknown This is because the uninitialized reference may be an alias to the reference being 528 // initialized, but we can't know that until the object register's type is known 529 530 for (int i = 0; i < preRegisterMap.length; i++) { 531 RegisterType registerType = preRegisterMap[i]; 532 if (registerType.category == RegisterType.UNINIT_REF || 533 registerType.category == RegisterType.UNINIT_THIS) { 534 setRegisters.add(i); 535 } 536 } 537 } 538 } 539 540 // On art, the optimizer will often nop out a check-cast instruction after an instance-of instruction. 541 // Normally, check-cast is where the register type actually changes. 542 // In order to correctly handle this case, we have to propagate the narrowed register type to the appropriate 543 // branch of the following if-eqz/if-nez 544 if (instructionIndex > 0 && 545 methodAnalyzer.getClassPath().isArt() && 546 getPredecessorCount() == 1 && 547 (instruction.getOpcode() == Opcode.IF_EQZ || instruction.getOpcode() == Opcode.IF_NEZ)) { 548 549 AnalyzedInstruction prevInstruction = predecessors.first(); 550 if (prevInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && 551 MethodAnalyzer.canPropagateTypeAfterInstanceOf( 552 prevInstruction, this, methodAnalyzer.getClassPath())) { 553 Instruction22c instanceOfInstruction = (Instruction22c)prevInstruction.instruction; 554 setRegisters.add(instanceOfInstruction.getRegisterB()); 555 556 // Additionally, there may be a move instruction just before the instance-of, in order to put the value 557 // into a register that is addressable by the instance-of. In this case, we also need to propagate the 558 // new register type for the original register that the value was moved from. 559 // In some cases, the instance-of may have multiple predecessors. In this case, we should only do the 560 // propagation if all predecessors are move-object instructions for the same source register 561 // TODO: do we need to do some sort of additional check that these multiple move-object predecessors actually refer to the same value? 562 if (instructionIndex > 1) { 563 int originalSourceRegister = -1; 564 565 RegisterType newType = null; 566 567 for (AnalyzedInstruction prevPrevAnalyzedInstruction : prevInstruction.predecessors) { 568 Opcode opcode = prevPrevAnalyzedInstruction.instruction.getOpcode(); 569 if (opcode == Opcode.MOVE_OBJECT || opcode == Opcode.MOVE_OBJECT_16 || 570 opcode == Opcode.MOVE_OBJECT_FROM16) { 571 TwoRegisterInstruction moveInstruction = 572 ((TwoRegisterInstruction)prevPrevAnalyzedInstruction.instruction); 573 RegisterType originalType = 574 prevPrevAnalyzedInstruction.getPostInstructionRegisterType( 575 moveInstruction.getRegisterB()); 576 if (moveInstruction.getRegisterA() != instanceOfInstruction.getRegisterB()) { 577 originalSourceRegister = -1; 578 break; 579 } 580 if (originalType.type == null) { 581 originalSourceRegister = -1; 582 break; 583 } 584 585 if (newType == null) { 586 newType = RegisterType.getRegisterType(methodAnalyzer.getClassPath(), 587 (TypeReference)instanceOfInstruction.getReference()); 588 } 589 590 if (MethodAnalyzer.isNotWideningConversion(originalType, newType)) { 591 if (originalSourceRegister != -1) { 592 if (originalSourceRegister != moveInstruction.getRegisterB()) { 593 originalSourceRegister = -1; 594 break; 595 } 596 } else { 597 originalSourceRegister = moveInstruction.getRegisterB(); 598 } 599 } 600 } else { 601 originalSourceRegister = -1; 602 break; 603 } 604 } 605 if (originalSourceRegister != -1) { 606 setRegisters.add(originalSourceRegister); 607 } 608 } 609 } 610 } 611 612 return setRegisters; 613 } 614 615 public int getDestinationRegister() { 616 if (!this.instruction.getOpcode().setsRegister()) { 617 throw new ExceptionWithContext("Cannot call getDestinationRegister() for an instruction that doesn't " + 618 "store a value"); 619 } 620 return ((OneRegisterInstruction)instruction).getRegisterA(); 621 } 622 623 public int getRegisterCount() { 624 return postRegisterMap.length; 625 } 626 627 @Nonnull 628 public RegisterType getPostInstructionRegisterType(int registerNumber) { 629 return postRegisterMap[registerNumber]; 630 } 631 632 @Nonnull 633 public RegisterType getPreInstructionRegisterType(int registerNumber) { 634 return preRegisterMap[registerNumber]; 635 } 636 637 public int compareTo(@Nonnull AnalyzedInstruction analyzedInstruction) { 638 if (instructionIndex < analyzedInstruction.instructionIndex) { 639 return -1; 640 } else if (instructionIndex == analyzedInstruction.instructionIndex) { 641 return 0; 642 } else { 643 return 1; 644 } 645 } 646 647 private static class PredecessorOverrideKey { 648 public final AnalyzedInstruction analyzedInstruction; 649 public final int registerNumber; 650 651 public PredecessorOverrideKey(AnalyzedInstruction analyzedInstruction, int registerNumber) { 652 this.analyzedInstruction = analyzedInstruction; 653 this.registerNumber = registerNumber; 654 } 655 656 @Override public boolean equals(Object o) { 657 if (this == o) return true; 658 if (o == null || getClass() != o.getClass()) return false; 659 PredecessorOverrideKey that = (PredecessorOverrideKey)o; 660 return com.google.common.base.Objects.equal(registerNumber, that.registerNumber) && 661 Objects.equal(analyzedInstruction, that.analyzedInstruction); 662 } 663 664 @Override public int hashCode() { 665 return Objects.hashCode(analyzedInstruction, registerNumber); 666 } 667 } 668 } 669 670