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 * Returns the count of reachable blocks in this method: blocks that have 343 * predecessors (or are the start block) 344 * 345 * @return {@code >= 0;} number of reachable basic blocks 346 */ getCountReachableBlocks()347 public int getCountReachableBlocks() { 348 int ret = 0; 349 350 for (SsaBasicBlock b : blocks) { 351 // Blocks that have been disconnected don't count. 352 if (b.isReachable()) { 353 ret++; 354 } 355 } 356 357 return ret; 358 } 359 360 /** 361 * Computes reachability for all blocks in the method. First clears old 362 * values from all blocks, then starts with the entry block and walks down 363 * the control flow graph, marking all blocks it finds as reachable. 364 */ computeReachability()365 public void computeReachability() { 366 for (SsaBasicBlock block : blocks) { 367 block.setReachable(0); 368 } 369 370 ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>(); 371 blockList.add(this.getEntryBlock()); 372 373 while (!blockList.isEmpty()) { 374 SsaBasicBlock block = blockList.remove(0); 375 if (block.isReachable()) continue; 376 377 block.setReachable(1); 378 BitSet succs = block.getSuccessors(); 379 for (int i = succs.nextSetBit(0); i >= 0; 380 i = succs.nextSetBit(i + 1)) { 381 blockList.add(blocks.get(i)); 382 } 383 } 384 } 385 386 /** 387 * Remaps unversioned registers. 388 * 389 * @param mapper maps old registers to new. 390 */ mapRegisters(RegisterMapper mapper)391 public void mapRegisters(RegisterMapper mapper) { 392 for (SsaBasicBlock block : getBlocks()) { 393 for (SsaInsn insn : block.getInsns()) { 394 insn.mapRegisters(mapper); 395 } 396 } 397 398 registerCount = mapper.getNewRegisterCount(); 399 spareRegisterBase = registerCount; 400 } 401 402 /** 403 * Returns the insn that defines the given register 404 * @param reg register in question 405 * @return insn (actual instance from code) that defined this reg or null 406 * if reg is not defined. 407 */ getDefinitionForRegister(int reg)408 public SsaInsn getDefinitionForRegister(int reg) { 409 if (backMode) { 410 throw new RuntimeException("No def list in back mode"); 411 } 412 413 if (definitionList != null) { 414 return definitionList[reg]; 415 } 416 417 definitionList = new SsaInsn[getRegCount()]; 418 419 forEachInsn(new SsaInsn.Visitor() { 420 public void visitMoveInsn (NormalSsaInsn insn) { 421 definitionList[insn.getResult().getReg()] = insn; 422 } 423 public void visitPhiInsn (PhiInsn phi) { 424 definitionList[phi.getResult().getReg()] = phi; 425 } 426 public void visitNonMoveInsn (NormalSsaInsn insn) { 427 RegisterSpec result = insn.getResult(); 428 if (result != null) { 429 definitionList[insn.getResult().getReg()] = insn; 430 } 431 } 432 }); 433 434 return definitionList[reg]; 435 } 436 437 /** 438 * Builds useList and unmodifiableUseList. 439 */ buildUseList()440 private void buildUseList() { 441 if (backMode) { 442 throw new RuntimeException("No use list in back mode"); 443 } 444 445 useList = new ArrayList[registerCount]; 446 447 for (int i = 0; i < registerCount; i++) { 448 useList[i] = new ArrayList(); 449 } 450 451 forEachInsn(new SsaInsn.Visitor() { 452 /** {@inheritDoc} */ 453 public void visitMoveInsn (NormalSsaInsn insn) { 454 addToUses(insn); 455 } 456 /** {@inheritDoc} */ 457 public void visitPhiInsn (PhiInsn phi) { 458 addToUses(phi); 459 } 460 /** {@inheritDoc} */ 461 public void visitNonMoveInsn (NormalSsaInsn insn) { 462 addToUses(insn); 463 } 464 /** 465 * Adds specified insn to the uses list for all of its sources. 466 * @param insn {@code non-null;} insn to process 467 */ 468 private void addToUses(SsaInsn insn) { 469 RegisterSpecList rl = insn.getSources(); 470 int sz = rl.size(); 471 472 for (int i = 0; i < sz; i++) { 473 useList[rl.get(i).getReg()].add(insn); 474 } 475 } 476 }); 477 478 unmodifiableUseList = new List[registerCount]; 479 480 for (int i = 0; i < registerCount; i++) { 481 unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]); 482 } 483 } 484 485 /** 486 * Updates the use list for a single change in source register. 487 * 488 * @param insn {@code non-null;} insn being changed 489 * @param oldSource {@code null-ok;} The source that was used, if 490 * applicable 491 * @param newSource {@code non-null;} the new source being used 492 */ onSourceChanged(SsaInsn insn, RegisterSpec oldSource, RegisterSpec newSource)493 /*package*/ void onSourceChanged(SsaInsn insn, 494 RegisterSpec oldSource, RegisterSpec newSource) { 495 if (useList == null) return; 496 497 if (oldSource != null) { 498 int reg = oldSource.getReg(); 499 useList[reg].remove(insn); 500 } 501 502 int reg = newSource.getReg(); 503 if (useList.length <= reg) { 504 useList = null; 505 return; 506 } 507 useList[reg].add(insn); 508 } 509 510 /** 511 * Updates the use list for a source list change. 512 * 513 * @param insn {@code insn non-null;} insn being changed. 514 * {@code insn.getSources()} must return the new source list. 515 * @param oldSources {@code null-ok;} list of sources that were 516 * previously used 517 */ onSourcesChanged(SsaInsn insn, RegisterSpecList oldSources)518 /*package*/ void onSourcesChanged(SsaInsn insn, 519 RegisterSpecList oldSources) { 520 if (useList == null) return; 521 522 if (oldSources != null) { 523 removeFromUseList(insn, oldSources); 524 } 525 526 RegisterSpecList sources = insn.getSources(); 527 int szNew = sources.size(); 528 529 for (int i = 0; i < szNew; i++) { 530 int reg = sources.get(i).getReg(); 531 useList[reg].add(insn); 532 } 533 } 534 535 /** 536 * Removes a given {@code insn} from the use lists for the given 537 * {@code oldSources} (rather than the sources currently 538 * returned by insn.getSources()). 539 * 540 * @param insn {@code non-null;} insn in question 541 * @param oldSources {@code null-ok;} registers whose use lists 542 * {@code insn} should be removed form 543 */ removeFromUseList(SsaInsn insn, RegisterSpecList oldSources)544 private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) { 545 if (oldSources == null) { 546 return; 547 } 548 549 int szNew = oldSources.size(); 550 for (int i = 0; i < szNew; i++) { 551 if (!useList[oldSources.get(i).getReg()].remove(insn)) { 552 throw new RuntimeException("use not found"); 553 } 554 } 555 } 556 557 /** 558 * Adds an insn to both the use and def lists. For use when adding 559 * a new insn to the method. 560 * 561 * @param insn {@code non-null;} insn to add 562 */ onInsnAdded(SsaInsn insn)563 /*package*/ void onInsnAdded(SsaInsn insn) { 564 onSourcesChanged(insn, null); 565 updateOneDefinition(insn, null); 566 } 567 568 /** 569 * Removes an instruction from use and def lists. For use during 570 * instruction removal. 571 * 572 * @param insn {@code non-null;} insn to remove 573 */ onInsnRemoved(SsaInsn insn)574 /*package*/ void onInsnRemoved(SsaInsn insn) { 575 if (useList != null) { 576 removeFromUseList(insn, insn.getSources()); 577 } 578 579 RegisterSpec resultReg = insn.getResult(); 580 if (definitionList != null && resultReg != null) { 581 definitionList[resultReg.getReg()] = null; 582 } 583 } 584 585 /** 586 * Indicates that the instruction list has changed or the SSA register 587 * count has increased, so that internal datastructures that rely on 588 * it should be rebuild. In general, the various other on* methods 589 * should be called in preference when changes occur if they are 590 * applicable. 591 */ onInsnsChanged()592 public void onInsnsChanged() { 593 // Definition list will need to be recomputed 594 definitionList = null; 595 596 // Use list will need to be recomputed 597 useList = null; 598 unmodifiableUseList = null; 599 } 600 601 /** 602 * Updates a single definition. 603 * 604 * @param insn {@code non-null;} insn who's result should be recorded as 605 * a definition 606 * @param oldResult {@code null-ok;} a previous result that should 607 * be no longer considered a definition by this insn 608 */ updateOneDefinition(SsaInsn insn, RegisterSpec oldResult)609 /*package*/ void updateOneDefinition(SsaInsn insn, 610 RegisterSpec oldResult) { 611 if (definitionList == null) return; 612 613 if (oldResult != null) { 614 int reg = oldResult.getReg(); 615 definitionList[reg] = null; 616 } 617 618 RegisterSpec resultReg = insn.getResult(); 619 620 if (resultReg != null) { 621 int reg = resultReg.getReg(); 622 623 if (definitionList[reg] != null) { 624 throw new RuntimeException("Duplicate add of insn"); 625 } else { 626 definitionList[resultReg.getReg()] = insn; 627 } 628 } 629 } 630 631 /** 632 * Returns the list of all source uses (not results) for a register. 633 * 634 * @param reg register in question 635 * @return unmodifiable instruction list 636 */ getUseListForRegister(int reg)637 public List<SsaInsn> getUseListForRegister(int reg) { 638 639 if (unmodifiableUseList == null) { 640 buildUseList(); 641 } 642 643 return unmodifiableUseList[reg]; 644 } 645 646 /** 647 * Returns a modifiable copy of the register use list. 648 * 649 * @return modifiable copy of the use-list, indexed by register 650 */ getUseListCopy()651 public ArrayList<SsaInsn>[] getUseListCopy() { 652 if (useList == null) { 653 buildUseList(); 654 } 655 656 ArrayList<SsaInsn>[] useListCopy 657 = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]); 658 659 for (int i = 0; i < registerCount; i++) { 660 useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i])); 661 } 662 663 return useListCopy; 664 } 665 666 /** 667 * Checks to see if the given SSA reg is ever associated with a local 668 * local variable. Each SSA reg may be associated with at most one 669 * local var. 670 * 671 * @param spec {@code non-null;} ssa reg 672 * @return true if reg is ever associated with a local 673 */ isRegALocal(RegisterSpec spec)674 public boolean isRegALocal(RegisterSpec spec) { 675 SsaInsn defn = getDefinitionForRegister(spec.getReg()); 676 677 if (defn == null) { 678 // version 0 registers are never used as locals 679 return false; 680 } 681 682 // Does the definition have a local associated with it? 683 if (defn.getLocalAssignment() != null) return true; 684 685 // If not, is there a mark-local insn? 686 for (SsaInsn use : getUseListForRegister(spec.getReg())) { 687 Insn insn = use.getOriginalRopInsn(); 688 689 if (insn != null 690 && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { 691 return true; 692 } 693 } 694 695 return false; 696 } 697 698 /** 699 * Sets the new register count after renaming. 700 * 701 * @param newRegCount new register count 702 */ setNewRegCount(int newRegCount)703 /*package*/ void setNewRegCount(int newRegCount) { 704 registerCount = newRegCount; 705 spareRegisterBase = registerCount; 706 onInsnsChanged(); 707 } 708 709 /** 710 * Makes a new SSA register. For use after renaming has completed. 711 * 712 * @return {@code >=0;} new SSA register. 713 */ makeNewSsaReg()714 public int makeNewSsaReg() { 715 int reg = registerCount++; 716 spareRegisterBase = registerCount; 717 onInsnsChanged(); 718 return reg; 719 } 720 721 /** 722 * Visits all insns in this method. 723 * 724 * @param visitor {@code non-null;} callback interface 725 */ forEachInsn(SsaInsn.Visitor visitor)726 public void forEachInsn(SsaInsn.Visitor visitor) { 727 for (SsaBasicBlock block : blocks) { 728 block.forEachInsn(visitor); 729 } 730 } 731 732 /** 733 * Visits each phi insn in this method 734 * @param v {@code non-null;} callback. 735 * 736 */ forEachPhiInsn(PhiInsn.Visitor v)737 public void forEachPhiInsn(PhiInsn.Visitor v) { 738 for (SsaBasicBlock block : blocks) { 739 block.forEachPhiInsn(v); 740 } 741 } 742 743 744 /** 745 * Walks the basic block tree in depth-first order, calling the visitor 746 * method once for every block. This depth-first walk may be run forward 747 * from the method entry point or backwards from the method exit points. 748 * 749 * @param reverse true if this should walk backwards from the exit points 750 * @param v {@code non-null;} callback interface. {@code parent} is set 751 * unless this is the root node 752 */ forEachBlockDepthFirst(boolean reverse, SsaBasicBlock.Visitor v)753 public void forEachBlockDepthFirst(boolean reverse, 754 SsaBasicBlock.Visitor v) { 755 BitSet visited = new BitSet(blocks.size()); 756 757 // We push the parent first, then the child on the stack. 758 Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); 759 760 SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock(); 761 762 if (rootBlock == null) { 763 // in the case there's no exit block 764 return; 765 } 766 767 stack.add(null); // Start with null parent. 768 stack.add(rootBlock); 769 770 while (stack.size() > 0) { 771 SsaBasicBlock cur = stack.pop(); 772 SsaBasicBlock parent = stack.pop(); 773 774 if (!visited.get(cur.getIndex())) { 775 BitSet children 776 = reverse ? cur.getPredecessors() : cur.getSuccessors(); 777 for (int i = children.nextSetBit(0); i >= 0 778 ; i = children.nextSetBit(i + 1)) { 779 stack.add(cur); 780 stack.add(blocks.get(i)); 781 } 782 visited.set(cur.getIndex()); 783 v.visitBlock(cur, parent); 784 } 785 } 786 } 787 788 /** 789 * Visits blocks in dom-tree order, starting at the current node. 790 * The {@code parent} parameter of the Visitor.visitBlock callback 791 * is currently always set to null. 792 * 793 * @param v {@code non-null;} callback interface 794 */ forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v)795 public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) { 796 BitSet visited = new BitSet(getBlocks().size()); 797 Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>(); 798 799 stack.add(getEntryBlock()); 800 801 while (stack.size() > 0) { 802 SsaBasicBlock cur = stack.pop(); 803 ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren(); 804 805 if (!visited.get(cur.getIndex())) { 806 // We walk the tree this way for historical reasons... 807 for (int i = curDomChildren.size() - 1; i >= 0; i--) { 808 SsaBasicBlock child = curDomChildren.get(i); 809 stack.add(child); 810 } 811 visited.set(cur.getIndex()); 812 v.visitBlock(cur, null); 813 } 814 } 815 } 816 817 /** 818 * Deletes all insns in the set from this method. 819 * 820 * @param deletedInsns {@code non-null;} insns to delete 821 */ deleteInsns(Set<SsaInsn> deletedInsns)822 public void deleteInsns(Set<SsaInsn> deletedInsns) { 823 for (SsaBasicBlock block : getBlocks()) { 824 ArrayList<SsaInsn> insns = block.getInsns(); 825 826 for (int i = insns.size() - 1; i >= 0; i--) { 827 SsaInsn insn = insns.get(i); 828 829 if (deletedInsns.contains(insn)) { 830 onInsnRemoved(insn); 831 insns.remove(i); 832 } 833 } 834 835 // Check to see if we need to add a GOTO 836 837 int insnsSz = insns.size(); 838 SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1); 839 840 if (block != getExitBlock() && (insnsSz == 0 841 || lastInsn.getOriginalRopInsn() == null 842 || lastInsn.getOriginalRopInsn().getOpcode() 843 .getBranchingness() == Rop.BRANCH_NONE)) { 844 // We managed to eat a throwable insn 845 846 Insn gotoInsn = new PlainInsn(Rops.GOTO, 847 SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY); 848 insns.add(SsaInsn.makeFromRop(gotoInsn, block)); 849 850 // Remove secondary successors from this block 851 BitSet succs = block.getSuccessors(); 852 for (int i = succs.nextSetBit(0); i >= 0; 853 i = succs.nextSetBit(i + 1)) { 854 if (i != block.getPrimarySuccessorIndex()) { 855 block.removeSuccessor(i); 856 } 857 } 858 } 859 } 860 } 861 862 /** 863 * Sets "back-convert mode". Set during back-conversion when registers 864 * are about to be mapped into a non-SSA namespace. When true, 865 * use and def lists are unavailable. 866 */ setBackMode()867 public void setBackMode() { 868 backMode = true; 869 useList = null; 870 definitionList = null; 871 } 872 } 873