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