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.ssa; 18 19import com.android.dx.rop.code.BasicBlockList; 20import com.android.dx.rop.code.Insn; 21import com.android.dx.rop.code.PlainInsn; 22import com.android.dx.rop.code.RegOps; 23import com.android.dx.rop.code.RegisterSpec; 24import com.android.dx.rop.code.RegisterSpecList; 25import com.android.dx.rop.code.Rop; 26import com.android.dx.rop.code.RopMethod; 27import com.android.dx.rop.code.Rops; 28import com.android.dx.rop.code.SourcePosition; 29import com.android.dx.util.IntList; 30 31import java.util.ArrayList; 32import java.util.BitSet; 33import java.util.Collections; 34import java.util.List; 35import java.util.Set; 36import java.util.Stack; 37 38/** 39 * A method in SSA form. 40 */ 41public final class SsaMethod { 42 /** basic blocks, indexed by block index */ 43 private ArrayList<SsaBasicBlock> blocks; 44 45 /** Index of first executed block in method */ 46 private int entryBlockIndex; 47 48 /** 49 * Index of exit block, which exists only in SSA form, 50 * or or {@code -1} if there is none 51 */ 52 private int exitBlockIndex; 53 54 /** total number of registers required */ 55 private int registerCount; 56 57 /** first register number to use for any temporary "spares" */ 58 private int spareRegisterBase; 59 60 /** current count of spare registers used */ 61 private int borrowedSpareRegisters; 62 63 /** really one greater than the max label */ 64 private int maxLabel; 65 66 /** the total width, in register-units, of the method's parameters */ 67 private final int paramWidth; 68 69 /** true if this method has no {@code this} pointer argument */ 70 private final boolean isStatic; 71 72 /** 73 * indexed by register: the insn where said register is defined or null 74 * if undefined. null until (lazily) created. 75 */ 76 private SsaInsn[] definitionList; 77 78 /** indexed by register: the list of all insns that use a register */ 79 private ArrayList<SsaInsn>[] useList; 80 81 /** A version of useList with each List unmodifiable */ 82 private List<SsaInsn>[] unmodifiableUseList; 83 84 /** 85 * "back-convert mode". Set during back-conversion when registers 86 * are about to be mapped into a non-SSA namespace. When true, 87 * use and def lists are unavailable. 88 * 89 * TODO: Remove this mode, and place the functionality elsewhere 90 */ 91 private boolean backMode; 92 93 /** 94 * @param ropMethod rop-form method to convert from 95 * @param paramWidth the total width, in register-units, of the 96 * method's parameters 97 * @param isStatic {@code true} if this method has no {@code this} 98 * pointer argument 99 */ 100 public static SsaMethod newFromRopMethod(RopMethod ropMethod, 101 int paramWidth, boolean isStatic) { 102 SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic); 103 104 result.convertRopToSsaBlocks(ropMethod); 105 106 return result; 107 } 108 109 /** 110 * Constructs an instance. 111 * 112 * @param ropMethod {@code non-null;} the original rop-form method that 113 * this instance is based on 114 * @param paramWidth the total width, in register-units, of the 115 * method's parameters 116 * @param isStatic {@code true} if this method has no {@code this} 117 * pointer argument 118 */ 119 private SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) { 120 this.paramWidth = paramWidth; 121 this.isStatic = isStatic; 122 this.backMode = false; 123 this.maxLabel = ropMethod.getBlocks().getMaxLabel(); 124 this.registerCount = ropMethod.getBlocks().getRegCount(); 125 this.spareRegisterBase = registerCount; 126 } 127 128 /** 129 * Builds a BitSet of block indices from a basic block list and a list 130 * of labels taken from Rop form. 131 * 132 * @param blocks Rop blocks 133 * @param labelList list of rop block labels 134 * @return BitSet of block indices 135 */ 136 static BitSet bitSetFromLabelList(BasicBlockList blocks, 137 IntList labelList) { 138 BitSet result = new BitSet(blocks.size()); 139 140 for (int i = 0, sz = labelList.size(); i < sz; i++) { 141 result.set(blocks.indexOfLabel(labelList.get(i))); 142 } 143 144 return result; 145 } 146 147 /** 148 * Builds an IntList of block indices from a basic block list and a list 149 * of labels taken from Rop form. 150 * 151 * @param ropBlocks Rop blocks 152 * @param labelList list of rop block labels 153 * @return IntList of block indices 154 */ 155 public static IntList indexListFromLabelList(BasicBlockList ropBlocks, 156 IntList labelList) { 157 158 IntList result = new IntList(labelList.size()); 159 160 for (int i = 0, sz = labelList.size(); i < sz; i++) { 161 result.add(ropBlocks.indexOfLabel(labelList.get(i))); 162 } 163 164 return result; 165 } 166 167 private void convertRopToSsaBlocks(RopMethod rmeth) { 168 BasicBlockList ropBlocks = rmeth.getBlocks(); 169 int sz = ropBlocks.size(); 170 171 blocks = new ArrayList<SsaBasicBlock>(sz + 2); 172 173 for (int i = 0; i < sz; i++) { 174 SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this); 175 blocks.add(sbb); 176 } 177 178 // Add an no-op entry block. 179 int origEntryBlockIndex = rmeth.getBlocks() 180 .indexOfLabel(rmeth.getFirstLabel()); 181 182 SsaBasicBlock entryBlock 183 = blocks.get(origEntryBlockIndex).insertNewPredecessor(); 184 185 entryBlockIndex = entryBlock.getIndex(); 186 exitBlockIndex = -1; // This gets made later. 187 } 188 189 /** 190 * Creates an exit block and attaches it to the CFG if this method 191 * exits. Methods that never exit will not have an exit block. This 192 * is called after edge-splitting and phi insertion, since the edges 193 * going into the exit block should not be considered in those steps. 194 */ 195 /*package*/ void makeExitBlock() { 196 if (exitBlockIndex >= 0) { 197 throw new RuntimeException("must be called at most once"); 198 } 199 200 exitBlockIndex = blocks.size(); 201 SsaBasicBlock exitBlock 202 = new SsaBasicBlock(exitBlockIndex, maxLabel++, this); 203 204 blocks.add(exitBlock); 205 206 for (SsaBasicBlock block : blocks) { 207 block.exitBlockFixup(exitBlock); 208 } 209 210 if (exitBlock.getPredecessors().cardinality() == 0) { 211 // In cases where there is no exit... 212 blocks.remove(exitBlockIndex); 213 exitBlockIndex = -1; 214 maxLabel--; 215 } 216 } 217 218 /** 219 * Gets a new {@code GOTO} insn. 220 * 221 * @param block block to which this GOTO will be added 222 * (not it's destination!) 223 * @return an appropriately-constructed instance. 224 */ 225 private static SsaInsn getGoto(SsaBasicBlock block) { 226 return new NormalSsaInsn ( 227 new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO, 228 null, RegisterSpecList.EMPTY), block); 229 } 230 231 /** 232 * Makes a new basic block for this method, which is empty besides 233 * a single {@code GOTO}. Successors and predecessors are not yet 234 * set. 235 * 236 * @return new block 237 */ 238 public SsaBasicBlock makeNewGotoBlock() { 239 int newIndex = blocks.size(); 240 SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this); 241 242 newBlock.getInsns().add(getGoto(newBlock)); 243 blocks.add(newBlock); 244 245 return newBlock; 246 } 247 248 /** 249 * @return block index of first execution block 250 */ 251 public int getEntryBlockIndex() { 252 return entryBlockIndex; 253 } 254 255 /** 256 * @return first execution block 257 */ 258 public SsaBasicBlock getEntryBlock() { 259 return blocks.get(entryBlockIndex); 260 } 261 262 /** 263 * @return block index of exit block or {@code -1} if there is none 264 */ 265 public int getExitBlockIndex() { 266 return exitBlockIndex; 267 } 268 269 /** 270 * @return {@code null-ok;} block of exit block or {@code null} if 271 * there is none 272 */ 273 public SsaBasicBlock getExitBlock() { 274 return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex); 275 } 276 277 /** 278 * @param bi block index or {@code -1} for none 279 * @return rop label or {code -1} if {@code bi} was {@code -1} 280 */ 281 public int blockIndexToRopLabel(int bi) { 282 if (bi < 0) { 283 return -1; 284 } 285 return blocks.get(bi).getRopLabel(); 286 } 287 288 /** 289 * @return count of registers used in this method 290 */ 291 public int getRegCount() { 292 return registerCount; 293 } 294 295 /** 296 * @return the total width, in register units, of the method's 297 * parameters 298 */ 299 public int getParamWidth() { 300 return paramWidth; 301 } 302 303 /** 304 * Returns {@code true} if this is a static method. 305 * 306 * @return {@code true} if this is a static method 307 */ 308 public boolean isStatic() { 309 return isStatic; 310 } 311 312 /** 313 * Borrows a register to use as a temp. Used in the phi removal process. 314 * Call returnSpareRegisters() when done. 315 * 316 * @param category width (1 or 2) of the register 317 * @return register number to use 318 */ 319 public int borrowSpareRegister(int category) { 320 int result = spareRegisterBase + borrowedSpareRegisters; 321 322 borrowedSpareRegisters += category; 323 registerCount = Math.max(registerCount, result + category); 324 325 return result; 326 } 327 328 /** 329 * Returns all borrowed registers. 330 */ 331 public void returnSpareRegisters() { 332 borrowedSpareRegisters = 0; 333 } 334 335 /** 336 * @return {@code non-null;} basic block list. Do not modify. 337 */ 338 public ArrayList<SsaBasicBlock> getBlocks() { 339 return blocks; 340 } 341 342 /** 343 * Returns the count of reachable blocks in this method: blocks that have 344 * predecessors (or are the start block) 345 * 346 * @return {@code >= 0;} number of reachable basic blocks 347 */ 348 public int getCountReachableBlocks() { 349 int ret = 0; 350 351 for (SsaBasicBlock b : blocks) { 352 // Blocks that have been disconnected don't count. 353 if (b.isReachable()) { 354 ret++; 355 } 356 } 357 358 return ret; 359 } 360 361 /** 362 * Computes reachability for all blocks in the method. First clears old 363 * values from all blocks, then starts with the entry block and walks down 364 * the control flow graph, marking all blocks it finds as reachable. 365 */ 366 public void computeReachability() { 367 for (SsaBasicBlock block : blocks) { 368 block.setReachable(0); 369 } 370 371 ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>(); 372 blockList.add(this.getEntryBlock()); 373 374 while (!blockList.isEmpty()) { 375 SsaBasicBlock block = blockList.remove(0); 376 if (block.isReachable()) continue; 377 378 block.setReachable(1); 379 BitSet succs = block.getSuccessors(); 380 for (int i = succs.nextSetBit(0); i >= 0; 381 i = succs.nextSetBit(i + 1)) { 382 blockList.add(blocks.get(i)); 383 } 384 } 385 } 386 387 /** 388 * Remaps unversioned registers. 389 * 390 * @param mapper maps old registers to new. 391 */ 392 public void mapRegisters(RegisterMapper mapper) { 393 for (SsaBasicBlock block : getBlocks()) { 394 for (SsaInsn insn : block.getInsns()) { 395 insn.mapRegisters(mapper); 396 } 397 } 398 399 registerCount = mapper.getNewRegisterCount(); 400 spareRegisterBase = registerCount; 401 } 402 403 /** 404 * Returns the insn that defines the given register 405 * @param reg register in question 406 * @return insn (actual instance from code) that defined this reg or null 407 * if reg is not defined. 408 */ 409 public SsaInsn getDefinitionForRegister(int reg) { 410 if (backMode) { 411 throw new RuntimeException("No def list in back mode"); 412 } 413 414 if (definitionList != null) { 415 return definitionList[reg]; 416 } 417 418 definitionList = new SsaInsn[getRegCount()]; 419 420 forEachInsn(new SsaInsn.Visitor() { 421 public void visitMoveInsn (NormalSsaInsn insn) { 422 definitionList[insn.getResult().getReg()] = insn; 423 } 424 public void visitPhiInsn (PhiInsn phi) { 425 definitionList[phi.getResult().getReg()] = phi; 426 } 427 public void visitNonMoveInsn (NormalSsaInsn insn) { 428 RegisterSpec result = insn.getResult(); 429 if (result != null) { 430 definitionList[insn.getResult().getReg()] = insn; 431 } 432 } 433 }); 434 435 return definitionList[reg]; 436 } 437 438 /** 439 * Builds useList and unmodifiableUseList. 440 */ 441 private void buildUseList() { 442 if (backMode) { 443 throw new RuntimeException("No use list in back mode"); 444 } 445 446 useList = new ArrayList[registerCount]; 447 448 for (int i = 0; i < registerCount; i++) { 449 useList[i] = new ArrayList(); 450 } 451 452 forEachInsn(new SsaInsn.Visitor() { 453 /** {@inheritDoc} */ 454 public void visitMoveInsn (NormalSsaInsn insn) { 455 addToUses(insn); 456 } 457 /** {@inheritDoc} */ 458 public void visitPhiInsn (PhiInsn phi) { 459 addToUses(phi); 460 } 461 /** {@inheritDoc} */ 462 public void visitNonMoveInsn (NormalSsaInsn insn) { 463 addToUses(insn); 464 } 465 /** 466 * Adds specified insn to the uses list for all of its sources. 467 * @param insn {@code non-null;} insn to process 468 */ 469 private void addToUses(SsaInsn insn) { 470 RegisterSpecList rl = insn.getSources(); 471 int sz = rl.size(); 472 473 for (int i = 0; i < sz; i++) { 474 useList[rl.get(i).getReg()].add(insn); 475 } 476 } 477 }); 478 479 unmodifiableUseList = new List[registerCount]; 480 481 for (int i = 0; i < registerCount; i++) { 482 unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]); 483 } 484 } 485 486 /** 487 * Updates the use list for a single change in source register. 488 * 489 * @param insn {@code non-null;} insn being changed 490 * @param oldSource {@code null-ok;} The source that was used, if 491 * applicable 492 * @param newSource {@code non-null;} the new source being used 493 */ 494 /*package*/ void onSourceChanged(SsaInsn insn, 495 RegisterSpec oldSource, RegisterSpec newSource) { 496 if (useList == null) return; 497 498 if (oldSource != null) { 499 int reg = oldSource.getReg(); 500 useList[reg].remove(insn); 501 } 502 503 int reg = newSource.getReg(); 504 if (useList.length <= reg) { 505 useList = null; 506 return; 507 } 508 useList[reg].add(insn); 509 } 510 511 /** 512 * Updates the use list for a source list change. 513 * 514 * @param insn {@code insn non-null;} insn being changed. 515 * {@code insn.getSources()} must return the new source list. 516 * @param oldSources {@code null-ok;} list of sources that were 517 * previously used 518 */ 519 /*package*/ void onSourcesChanged(SsaInsn insn, 520 RegisterSpecList oldSources) { 521 if (useList == null) return; 522 523 if (oldSources != null) { 524 removeFromUseList(insn, oldSources); 525 } 526 527 RegisterSpecList sources = insn.getSources(); 528 int szNew = sources.size(); 529 530 for (int i = 0; i < szNew; i++) { 531 int reg = sources.get(i).getReg(); 532 useList[reg].add(insn); 533 } 534 } 535 536 /** 537 * Removes a given {@code insn} from the use lists for the given 538 * {@code oldSources} (rather than the sources currently 539 * returned by insn.getSources()). 540 * 541 * @param insn {@code non-null;} insn in question 542 * @param oldSources {@code null-ok;} registers whose use lists 543 * {@code insn} should be removed form 544 */ 545 private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) { 546 if (oldSources == null) { 547 return; 548 } 549 550 int szNew = oldSources.size(); 551 for (int i = 0; i < szNew; i++) { 552 if (!useList[oldSources.get(i).getReg()].remove(insn)) { 553 throw new RuntimeException("use not found"); 554 } 555 } 556 } 557 558 /** 559 * Adds an insn to both the use and def lists. For use when adding 560 * a new insn to the method. 561 * 562 * @param insn {@code non-null;} insn to add 563 */ 564 /*package*/ void onInsnAdded(SsaInsn insn) { 565 onSourcesChanged(insn, null); 566 updateOneDefinition(insn, null); 567 } 568 569 /** 570 * Removes an instruction from use and def lists. For use during 571 * instruction removal. 572 * 573 * @param insn {@code non-null;} insn to remove 574 */ 575 /*package*/ void onInsnRemoved(SsaInsn insn) { 576 if (useList != null) { 577 removeFromUseList(insn, insn.getSources()); 578 } 579 580 RegisterSpec resultReg = insn.getResult(); 581 if (definitionList != null && resultReg != null) { 582 definitionList[resultReg.getReg()] = null; 583 } 584 } 585 586 /** 587 * Indicates that the instruction list has changed or the SSA register 588 * count has increased, so that internal datastructures that rely on 589 * it should be rebuild. In general, the various other on* methods 590 * should be called in preference when changes occur if they are 591 * applicable. 592 */ 593 public void onInsnsChanged() { 594 // Definition list will need to be recomputed 595 definitionList = null; 596 597 // Use list will need to be recomputed 598 useList = null; 599 unmodifiableUseList = null; 600 } 601 602 /** 603 * Updates a single definition. 604 * 605 * @param insn {@code non-null;} insn who's result should be recorded as 606 * a definition 607 * @param oldResult {@code null-ok;} a previous result that should 608 * be no longer considered a definition by this insn 609 */ 610 /*package*/ void updateOneDefinition(SsaInsn insn, 611 RegisterSpec oldResult) { 612 if (definitionList == null) return; 613 614 if (oldResult != null) { 615 int reg = oldResult.getReg(); 616 definitionList[reg] = null; 617 } 618 619 RegisterSpec resultReg = insn.getResult(); 620 621 if (resultReg != null) { 622 int reg = resultReg.getReg(); 623 624 if (definitionList[reg] != null) { 625 throw new RuntimeException("Duplicate add of insn"); 626 } else { 627 definitionList[resultReg.getReg()] = insn; 628 } 629 } 630 } 631 632 /** 633 * Returns the list of all source uses (not results) for a register. 634 * 635 * @param reg register in question 636 * @return unmodifiable instruction list 637 */ 638 public List<SsaInsn> getUseListForRegister(int reg) { 639 640 if (unmodifiableUseList == null) { 641 buildUseList(); 642 } 643 644 return unmodifiableUseList[reg]; 645 } 646 647 /** 648 * Returns a modifiable copy of the register use list. 649 * 650 * @return modifiable copy of the use-list, indexed by register 651 */ 652 public ArrayList<SsaInsn>[] getUseListCopy() { 653 if (useList == null) { 654 buildUseList(); 655 } 656 657 ArrayList<SsaInsn>[] useListCopy 658 = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]); 659 660 for (int i = 0; i < registerCount; i++) { 661 useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i])); 662 } 663 664 return useListCopy; 665 } 666 667 /** 668 * Checks to see if the given SSA reg is ever associated with a local 669 * local variable. Each SSA reg may be associated with at most one 670 * local var. 671 * 672 * @param spec {@code non-null;} ssa reg 673 * @return true if reg is ever associated with a local 674 */ 675 public boolean isRegALocal(RegisterSpec spec) { 676 SsaInsn defn = getDefinitionForRegister(spec.getReg()); 677 678 if (defn == null) { 679 // version 0 registers are never used as locals 680 return false; 681 } 682 683 // Does the definition have a local associated with it? 684 if (defn.getLocalAssignment() != null) return true; 685 686 // If not, is there a mark-local insn? 687 for (SsaInsn use : getUseListForRegister(spec.getReg())) { 688 Insn insn = use.getOriginalRopInsn(); 689 690 if (insn != null 691 && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { 692 return true; 693 } 694 } 695 696 return false; 697 } 698 699 /** 700 * Sets the new register count after renaming. 701 * 702 * @param newRegCount new register count 703 */ 704 /*package*/ void setNewRegCount(int newRegCount) { 705 registerCount = newRegCount; 706 spareRegisterBase = registerCount; 707 onInsnsChanged(); 708 } 709 710 /** 711 * Makes a new SSA register. For use after renaming has completed. 712 * 713 * @return {@code >=0;} new SSA register. 714 */ 715 public int makeNewSsaReg() { 716 int reg = registerCount++; 717 spareRegisterBase = registerCount; 718 onInsnsChanged(); 719 return reg; 720 } 721 722 /** 723 * Visits all insns in this method. 724 * 725 * @param visitor {@code non-null;} callback interface 726 */ 727 public void forEachInsn(SsaInsn.Visitor visitor) { 728 for (SsaBasicBlock block : blocks) { 729 block.forEachInsn(visitor); 730 } 731 } 732 733 /** 734 * Visits each phi insn in this method 735 * @param v {@code non-null;} callback. 736 * 737 */ 738 public void forEachPhiInsn(PhiInsn.Visitor v) { 739 for (SsaBasicBlock block : blocks) { 740 block.forEachPhiInsn(v); 741 } 742 } 743 744 745 /** 746 * Walks the basic block tree in depth-first order, calling the visitor 747 * method once for every block. This depth-first walk may be run forward 748 * from the method entry point or backwards from the method exit points. 749 * 750 * @param reverse true if this should walk backwards from the exit points 751 * @param v {@code non-null;} callback interface. {@code parent} is set 752 * unless this is the root node 753 */ 754 public void forEachBlockDepthFirst(boolean reverse, 755 SsaBasicBlock.Visitor v) { 756 BitSet visited = new BitSet(blocks.size()); 757 758 // We push the parent first, then the child on the stack. 759 Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); 760 761 SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock(); 762 763 if (rootBlock == null) { 764 // in the case there's no exit block 765 return; 766 } 767 768 stack.add(null); // Start with null parent. 769 stack.add(rootBlock); 770 771 while (stack.size() > 0) { 772 SsaBasicBlock cur = stack.pop(); 773 SsaBasicBlock parent = stack.pop(); 774 775 if (!visited.get(cur.getIndex())) { 776 BitSet children 777 = reverse ? cur.getPredecessors() : cur.getSuccessors(); 778 for (int i = children.nextSetBit(0); i >= 0 779 ; i = children.nextSetBit(i + 1)) { 780 stack.add(cur); 781 stack.add(blocks.get(i)); 782 } 783 visited.set(cur.getIndex()); 784 v.visitBlock(cur, parent); 785 } 786 } 787 } 788 789 /** 790 * Visits blocks in dom-tree order, starting at the current node. 791 * The {@code parent} parameter of the Visitor.visitBlock callback 792 * is currently always set to null. 793 * 794 * @param v {@code non-null;} callback interface 795 */ 796 public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) { 797 BitSet visited = new BitSet(getBlocks().size()); 798 Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); 799 800 stack.add(getEntryBlock()); 801 802 while (stack.size() > 0) { 803 SsaBasicBlock cur = stack.pop(); 804 ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren(); 805 806 if (!visited.get(cur.getIndex())) { 807 // We walk the tree this way for historical reasons... 808 for (int i = curDomChildren.size() - 1; i >= 0; i--) { 809 SsaBasicBlock child = curDomChildren.get(i); 810 stack.add(child); 811 } 812 visited.set(cur.getIndex()); 813 v.visitBlock(cur, null); 814 } 815 } 816 } 817 818 /** 819 * Deletes all insns in the set from this method. 820 * 821 * @param deletedInsns {@code non-null;} insns to delete 822 */ 823 public void deleteInsns(Set<SsaInsn> deletedInsns) { 824 for (SsaBasicBlock block : getBlocks()) { 825 ArrayList<SsaInsn> insns = block.getInsns(); 826 827 for (int i = insns.size() - 1; i >= 0; i--) { 828 SsaInsn insn = insns.get(i); 829 830 if (deletedInsns.contains(insn)) { 831 onInsnRemoved(insn); 832 insns.remove(i); 833 } 834 } 835 836 // Check to see if we need to add a GOTO 837 838 int insnsSz = insns.size(); 839 SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1); 840 841 if (block != getExitBlock() && (insnsSz == 0 842 || lastInsn.getOriginalRopInsn() == null 843 || lastInsn.getOriginalRopInsn().getOpcode() 844 .getBranchingness() == Rop.BRANCH_NONE)) { 845 // We managed to eat a throwable insn 846 847 Insn gotoInsn = new PlainInsn(Rops.GOTO, 848 SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY); 849 insns.add(SsaInsn.makeFromRop(gotoInsn, block)); 850 851 // Remove secondary successors from this block 852 BitSet succs = block.getSuccessors(); 853 for (int i = succs.nextSetBit(0); i >= 0; 854 i = succs.nextSetBit(i + 1)) { 855 if (i != block.getPrimarySuccessorIndex()) { 856 block.removeSuccessor(i); 857 } 858 } 859 } 860 } 861 } 862 863 /** 864 * Sets "back-convert mode". Set during back-conversion when registers 865 * are about to be mapped into a non-SSA namespace. When true, 866 * use and def lists are unavailable. 867 */ 868 public void setBackMode() { 869 backMode = true; 870 useList = null; 871 definitionList = null; 872 } 873} 874