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