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.dex.code; 18 19import com.android.dx.dex.DexOptions; 20import com.android.dx.io.Opcodes; 21import com.android.dx.rop.code.LocalItem; 22import com.android.dx.rop.code.RegisterSpec; 23import com.android.dx.rop.code.RegisterSpecList; 24import com.android.dx.rop.code.RegisterSpecSet; 25import com.android.dx.rop.code.SourcePosition; 26import com.android.dx.rop.cst.Constant; 27import com.android.dx.rop.cst.CstMemberRef; 28import com.android.dx.rop.cst.CstString; 29import com.android.dx.rop.cst.CstType; 30import com.android.dx.rop.type.Type; 31import com.android.dx.ssa.BasicRegisterMapper; 32 33import com.android.dex.DexException; 34import java.util.ArrayList; 35import java.util.BitSet; 36import java.util.HashSet; 37 38/** 39 * Processor for instruction lists, which takes a "first cut" of 40 * instruction selection as a basis and produces a "final cut" in the 41 * form of a {@link DalvInsnList} instance. 42 */ 43public final class OutputFinisher { 44 /** {@code non-null;} options for dex output */ 45 private final DexOptions dexOptions; 46 47 /** 48 * {@code >= 0;} register count for the method, not including any extra 49 * "reserved" registers needed to translate "difficult" instructions 50 */ 51 private final int unreservedRegCount; 52 53 /** {@code non-null;} the list of instructions, per se */ 54 private ArrayList<DalvInsn> insns; 55 56 /** whether any instruction has position info */ 57 private boolean hasAnyPositionInfo; 58 59 /** whether any instruction has local variable info */ 60 private boolean hasAnyLocalInfo; 61 62 /** 63 * {@code >= 0;} the count of reserved registers (low-numbered 64 * registers used when expanding instructions that can't be 65 * represented simply); becomes valid after a call to {@link 66 * #massageInstructions} 67 */ 68 private int reservedCount; 69 70 /** 71 * {@code >= 0;} the count of reserved registers just before parameters in order to align them. 72 */ 73 private int reservedParameterCount; 74 75 /** 76 * Size, in register units, of all the parameters to this method 77 */ 78 private final int paramSize; 79 80 /** 81 * Constructs an instance. It initially contains no instructions. 82 * 83 * @param dexOptions {@code non-null;} options for dex output 84 * @param initialCapacity {@code >= 0;} initial capacity of the 85 * instructions list 86 * @param regCount {@code >= 0;} register count for the method 87 * @param paramSize size, in register units, of all the parameters for this method 88 */ 89 public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount, int paramSize) { 90 this.dexOptions = dexOptions; 91 this.unreservedRegCount = regCount; 92 this.insns = new ArrayList<DalvInsn>(initialCapacity); 93 this.reservedCount = -1; 94 this.hasAnyPositionInfo = false; 95 this.hasAnyLocalInfo = false; 96 this.paramSize = paramSize; 97 } 98 99 /** 100 * Returns whether any of the instructions added to this instance 101 * come with position info. 102 * 103 * @return whether any of the instructions added to this instance 104 * come with position info 105 */ 106 public boolean hasAnyPositionInfo() { 107 return hasAnyPositionInfo; 108 } 109 110 /** 111 * Returns whether this instance has any local variable information. 112 * 113 * @return whether this instance has any local variable information 114 */ 115 public boolean hasAnyLocalInfo() { 116 return hasAnyLocalInfo; 117 } 118 119 /** 120 * Helper for {@link #add} which scrutinizes a single 121 * instruction for local variable information. 122 * 123 * @param insn {@code non-null;} instruction to scrutinize 124 * @return {@code true} iff the instruction refers to any 125 * named locals 126 */ 127 private static boolean hasLocalInfo(DalvInsn insn) { 128 if (insn instanceof LocalSnapshot) { 129 RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); 130 int size = specs.size(); 131 for (int i = 0; i < size; i++) { 132 if (hasLocalInfo(specs.get(i))) { 133 return true; 134 } 135 } 136 } else if (insn instanceof LocalStart) { 137 RegisterSpec spec = ((LocalStart) insn).getLocal(); 138 if (hasLocalInfo(spec)) { 139 return true; 140 } 141 } 142 143 return false; 144 } 145 146 /** 147 * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single 148 * register spec. 149 * 150 * @param spec {@code non-null;} spec to scrutinize 151 * @return {@code true} iff the spec refers to any 152 * named locals 153 */ 154 private static boolean hasLocalInfo(RegisterSpec spec) { 155 return (spec != null) 156 && (spec.getLocalItem().getName() != null); 157 } 158 159 /** 160 * Returns the set of all constants referred to by instructions added 161 * to this instance. 162 * 163 * @return {@code non-null;} the set of constants 164 */ 165 public HashSet<Constant> getAllConstants() { 166 HashSet<Constant> result = new HashSet<Constant>(20); 167 168 for (DalvInsn insn : insns) { 169 addConstants(result, insn); 170 } 171 172 return result; 173 } 174 175 /** 176 * Helper for {@link #getAllConstants} which adds all the info for 177 * a single instruction. 178 * 179 * @param result {@code non-null;} result set to add to 180 * @param insn {@code non-null;} instruction to scrutinize 181 */ 182 private static void addConstants(HashSet<Constant> result, 183 DalvInsn insn) { 184 if (insn instanceof CstInsn) { 185 Constant cst = ((CstInsn) insn).getConstant(); 186 result.add(cst); 187 } else if (insn instanceof LocalSnapshot) { 188 RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals(); 189 int size = specs.size(); 190 for (int i = 0; i < size; i++) { 191 addConstants(result, specs.get(i)); 192 } 193 } else if (insn instanceof LocalStart) { 194 RegisterSpec spec = ((LocalStart) insn).getLocal(); 195 addConstants(result, spec); 196 } 197 } 198 199 /** 200 * Helper for {@link #getAllConstants} which adds all the info for 201 * a single {@code RegisterSpec}. 202 * 203 * @param result {@code non-null;} result set to add to 204 * @param spec {@code null-ok;} register spec to add 205 */ 206 private static void addConstants(HashSet<Constant> result, 207 RegisterSpec spec) { 208 if (spec == null) { 209 return; 210 } 211 212 LocalItem local = spec.getLocalItem(); 213 CstString name = local.getName(); 214 CstString signature = local.getSignature(); 215 Type type = spec.getType(); 216 217 if (type != Type.KNOWN_NULL) { 218 result.add(CstType.intern(type)); 219 } 220 221 if (name != null) { 222 result.add(name); 223 } 224 225 if (signature != null) { 226 result.add(signature); 227 } 228 } 229 230 /** 231 * Adds an instruction to the output. 232 * 233 * @param insn {@code non-null;} the instruction to add 234 */ 235 public void add(DalvInsn insn) { 236 insns.add(insn); 237 updateInfo(insn); 238 } 239 240 /** 241 * Inserts an instruction in the output at the given offset. 242 * 243 * @param at {@code >= 0;} what index to insert at 244 * @param insn {@code non-null;} the instruction to insert 245 */ 246 public void insert(int at, DalvInsn insn) { 247 insns.add(at, insn); 248 updateInfo(insn); 249 } 250 251 /** 252 * Helper for {@link #add} and {@link #insert}, 253 * which updates the position and local info flags. 254 * 255 * @param insn {@code non-null;} an instruction that was just introduced 256 */ 257 private void updateInfo(DalvInsn insn) { 258 if (! hasAnyPositionInfo) { 259 SourcePosition pos = insn.getPosition(); 260 if (pos.getLine() >= 0) { 261 hasAnyPositionInfo = true; 262 } 263 } 264 265 if (! hasAnyLocalInfo) { 266 if (hasLocalInfo(insn)) { 267 hasAnyLocalInfo = true; 268 } 269 } 270 } 271 272 /** 273 * Reverses a branch which is buried a given number of instructions 274 * backward in the output. It is illegal to call this unless the 275 * indicated instruction really is a reversible branch. 276 * 277 * @param which how many instructions back to find the branch; 278 * {@code 0} is the most recently added instruction, 279 * {@code 1} is the instruction before that, etc. 280 * @param newTarget {@code non-null;} the new target for the 281 * reversed branch 282 */ 283 public void reverseBranch(int which, CodeAddress newTarget) { 284 int size = insns.size(); 285 int index = size - which - 1; 286 TargetInsn targetInsn; 287 288 try { 289 targetInsn = (TargetInsn) insns.get(index); 290 } catch (IndexOutOfBoundsException ex) { 291 // Translate the exception. 292 throw new IllegalArgumentException("too few instructions"); 293 } catch (ClassCastException ex) { 294 // Translate the exception. 295 throw new IllegalArgumentException("non-reversible instruction"); 296 } 297 298 /* 299 * No need to call this.set(), since the format and other info 300 * are the same. 301 */ 302 insns.set(index, targetInsn.withNewTargetAndReversed(newTarget)); 303 } 304 305 /** 306 * Assigns indices in all instructions that need them, using the 307 * given callback to perform lookups. This should be called before 308 * calling {@link #finishProcessingAndGetList}. 309 * 310 * @param callback {@code non-null;} callback object 311 */ 312 public void assignIndices(DalvCode.AssignIndicesCallback callback) { 313 for (DalvInsn insn : insns) { 314 if (insn instanceof CstInsn) { 315 assignIndices((CstInsn) insn, callback); 316 } 317 } 318 } 319 320 /** 321 * Helper for {@link #assignIndices} which does assignment for one 322 * instruction. 323 * 324 * @param insn {@code non-null;} the instruction 325 * @param callback {@code non-null;} the callback 326 */ 327 private static void assignIndices(CstInsn insn, 328 DalvCode.AssignIndicesCallback callback) { 329 Constant cst = insn.getConstant(); 330 int index = callback.getIndex(cst); 331 332 if (index >= 0) { 333 insn.setIndex(index); 334 } 335 336 if (cst instanceof CstMemberRef) { 337 CstMemberRef member = (CstMemberRef) cst; 338 CstType definer = member.getDefiningClass(); 339 index = callback.getIndex(definer); 340 if (index >= 0) { 341 insn.setClassIndex(index); 342 } 343 } 344 } 345 346 /** 347 * Does final processing on this instance and gets the output as 348 * a {@link DalvInsnList}. Final processing consists of: 349 * 350 * <ul> 351 * <li>optionally renumbering registers (to make room as needed for 352 * expanded instructions)</li> 353 * <li>picking a final opcode for each instruction</li> 354 * <li>rewriting instructions, because of register number, 355 * constant pool index, or branch target size issues</li> 356 * <li>assigning final addresses</li> 357 * </ul> 358 * 359 * <p><b>Note:</b> This method may only be called once per instance 360 * of this class.</p> 361 * 362 * @return {@code non-null;} the output list 363 * @throws UnsupportedOperationException if this method has 364 * already been called 365 */ 366 public DalvInsnList finishProcessingAndGetList() { 367 if (reservedCount >= 0) { 368 throw new UnsupportedOperationException("already processed"); 369 } 370 371 Dop[] opcodes = makeOpcodesArray(); 372 reserveRegisters(opcodes); 373 if (dexOptions.ALIGN_64BIT_REGS_IN_OUTPUT_FINISHER) { 374 align64bits(opcodes); 375 } 376 massageInstructions(opcodes); 377 assignAddressesAndFixBranches(); 378 379 return DalvInsnList.makeImmutable(insns, reservedCount + unreservedRegCount 380 + reservedParameterCount); 381 } 382 383 /** 384 * Helper for {@link #finishProcessingAndGetList}, which extracts 385 * the opcode out of each instruction into a separate array, to be 386 * further manipulated as things progress. 387 * 388 * @return {@code non-null;} the array of opcodes 389 */ 390 private Dop[] makeOpcodesArray() { 391 int size = insns.size(); 392 Dop[] result = new Dop[size]; 393 394 for (int i = 0; i < size; i++) { 395 result[i] = insns.get(i).getOpcode(); 396 } 397 398 return result; 399 } 400 401 /** 402 * Helper for {@link #finishProcessingAndGetList}, which figures 403 * out how many reserved registers are required and then reserving 404 * them. It also updates the given {@code opcodes} array so 405 * as to avoid extra work when constructing the massaged 406 * instruction list. 407 * 408 * @param opcodes {@code non-null;} array of per-instruction 409 * opcode selections 410 * @return true if reservedCount is expanded, false otherwise 411 */ 412 private boolean reserveRegisters(Dop[] opcodes) { 413 boolean reservedCountExpanded = false; 414 int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount; 415 416 /* 417 * Call calculateReservedCount() and then perform register 418 * reservation, repeatedly until no new reservations happen. 419 */ 420 for (;;) { 421 int newReservedCount = calculateReservedCount(opcodes); 422 if (oldReservedCount >= newReservedCount) { 423 break; 424 } 425 426 reservedCountExpanded = true; 427 428 int reservedDifference = newReservedCount - oldReservedCount; 429 int size = insns.size(); 430 431 for (int i = 0; i < size; i++) { 432 /* 433 * CodeAddress instance identity is used to link 434 * TargetInsns to their targets, so it is 435 * inappropriate to make replacements, and they don't 436 * have registers in any case. Hence, the instanceof 437 * test below. 438 */ 439 DalvInsn insn = insns.get(i); 440 if (!(insn instanceof CodeAddress)) { 441 /* 442 * No need to call this.set() since the format and 443 * other info are the same. 444 */ 445 insns.set(i, insn.withRegisterOffset(reservedDifference)); 446 } 447 } 448 449 oldReservedCount = newReservedCount; 450 } 451 452 reservedCount = oldReservedCount; 453 454 return reservedCountExpanded; 455 } 456 457 /** 458 * Helper for {@link #reserveRegisters}, which does one 459 * pass over the instructions, calculating the number of 460 * registers that need to be reserved. It also updates the 461 * {@code opcodes} list to help avoid extra work in future 462 * register reservation passes. 463 * 464 * @param opcodes {@code non-null;} array of per-instruction 465 * opcode selections 466 * @return {@code >= 0;} the count of reserved registers 467 */ 468 private int calculateReservedCount(Dop[] opcodes) { 469 int size = insns.size(); 470 471 /* 472 * Potential new value of reservedCount, which gets updated in the 473 * following loop. It starts out with the existing reservedCount 474 * and gets increased if it turns out that additional registers 475 * need to be reserved. 476 */ 477 int newReservedCount = reservedCount; 478 479 for (int i = 0; i < size; i++) { 480 DalvInsn insn = insns.get(i); 481 Dop originalOpcode = opcodes[i]; 482 Dop newOpcode = findOpcodeForInsn(insn, originalOpcode); 483 484 if (newOpcode == null) { 485 /* 486 * The instruction will need to be expanded, so find the 487 * expanded opcode and reserve registers for it. 488 */ 489 Dop expandedOp = findExpandedOpcodeForInsn(insn); 490 BitSet compatRegs = expandedOp.getFormat().compatibleRegs(insn); 491 int reserve = insn.getMinimumRegisterRequirement(compatRegs); 492 if (reserve > newReservedCount) { 493 newReservedCount = reserve; 494 } 495 } else if (originalOpcode == newOpcode) { 496 continue; 497 } 498 499 opcodes[i] = newOpcode; 500 } 501 502 return newReservedCount; 503 } 504 505 /** 506 * Attempts to fit the given instruction into a specific opcode, 507 * returning the opcode whose format that the instruction fits 508 * into or {@code null} to indicate that the instruction will need 509 * to be expanded. This fitting process starts with the given 510 * opcode as a first "best guess" and then pessimizes from there 511 * if necessary. 512 * 513 * @param insn {@code non-null;} the instruction in question 514 * @param guess {@code null-ok;} the current guess as to the best 515 * opcode; {@code null} means that no simple opcode fits 516 * @return {@code null-ok;} a possibly-different opcode; either a 517 * {@code non-null} good fit or {@code null} to indicate that no 518 * simple opcode fits 519 */ 520 private Dop findOpcodeForInsn(DalvInsn insn, Dop guess) { 521 /* 522 * Note: The initial guess might be null, meaning that an 523 * earlier call to this method already determined that there 524 * was no possible simple opcode fit. 525 */ 526 527 while (guess != null) { 528 if (guess.getFormat().isCompatible(insn)) { 529 /* 530 * Don't break out for const_string to generate jumbo version 531 * when option is enabled. 532 */ 533 if (!dexOptions.forceJumbo || 534 guess.getOpcode() != Opcodes.CONST_STRING) { 535 break; 536 } 537 } 538 539 guess = Dops.getNextOrNull(guess, dexOptions); 540 } 541 542 return guess; 543 } 544 545 /** 546 * Finds the proper opcode for the given instruction, ignoring 547 * register constraints. 548 * 549 * @param insn {@code non-null;} the instruction in question 550 * @return {@code non-null;} the opcode that fits 551 */ 552 private Dop findExpandedOpcodeForInsn(DalvInsn insn) { 553 Dop result = findOpcodeForInsn(insn.getLowRegVersion(), insn.getOpcode()); 554 if (result == null) { 555 throw new DexException("No expanded opcode for " + insn); 556 } 557 return result; 558 } 559 560 /** 561 * Helper for {@link #finishProcessingAndGetList}, which goes 562 * through each instruction in the output, making sure its opcode 563 * can accomodate its arguments. In cases where the opcode is 564 * unable to do so, this replaces the instruction with a larger 565 * instruction with identical semantics that <i>will</i> work. 566 * 567 * <p>This method may also reserve a number of low-numbered 568 * registers, renumbering the instructions' original registers, in 569 * order to have register space available in which to move 570 * very-high registers when expanding instructions into 571 * multi-instruction sequences. This expansion is done when no 572 * simple instruction format can be found for a given instruction that 573 * is able to accomodate that instruction's registers.</p> 574 * 575 * <p>This method ignores issues of branch target size, since 576 * final addresses aren't known at the point that this method is 577 * called.</p> 578 * 579 * @param opcodes {@code non-null;} array of per-instruction 580 * opcode selections 581 */ 582 private void massageInstructions(Dop[] opcodes) { 583 if (reservedCount == 0) { 584 /* 585 * The easy common case: No registers were reserved, so we 586 * merely need to replace any instructions whose format 587 * (and hence whose opcode) changed during the reservation 588 * pass, but all instructions will stay at their original 589 * indices, and the instruction list doesn't grow. 590 */ 591 int size = insns.size(); 592 593 for (int i = 0; i < size; i++) { 594 DalvInsn insn = insns.get(i); 595 Dop originalOpcode = insn.getOpcode(); 596 Dop currentOpcode = opcodes[i]; 597 598 if (originalOpcode != currentOpcode) { 599 insns.set(i, insn.withOpcode(currentOpcode)); 600 } 601 } 602 } else { 603 /* 604 * The difficult uncommon case: Some instructions have to be 605 * expanded to deal with high registers. 606 */ 607 insns = performExpansion(opcodes); 608 } 609 } 610 611 /** 612 * Helper for {@link #massageInstructions}, which constructs a 613 * replacement list, where each {link DalvInsn} instance that 614 * couldn't be represented simply (due to register representation 615 * problems) is expanded into a series of instances that together 616 * perform the proper function. 617 * 618 * @param opcodes {@code non-null;} array of per-instruction 619 * opcode selections 620 * @return {@code non-null;} the replacement list 621 */ 622 private ArrayList<DalvInsn> performExpansion(Dop[] opcodes) { 623 int size = insns.size(); 624 ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2); 625 626 ArrayList<CodeAddress> closelyBoundAddresses = new ArrayList<CodeAddress>(); 627 628 for (int i = 0; i < size; i++) { 629 DalvInsn insn = insns.get(i); 630 Dop originalOpcode = insn.getOpcode(); 631 Dop currentOpcode = opcodes[i]; 632 DalvInsn prefix; 633 DalvInsn suffix; 634 635 if (currentOpcode != null) { 636 // No expansion is necessary. 637 prefix = null; 638 suffix = null; 639 } else { 640 // Expansion is required. 641 currentOpcode = findExpandedOpcodeForInsn(insn); 642 BitSet compatRegs = 643 currentOpcode.getFormat().compatibleRegs(insn); 644 prefix = insn.expandedPrefix(compatRegs); 645 suffix = insn.expandedSuffix(compatRegs); 646 647 // Expand necessary registers to fit the new format 648 insn = insn.expandedVersion(compatRegs); 649 } 650 651 if (insn instanceof CodeAddress) { 652 // If we have a closely bound address, don't add it yet, 653 // because we need to add it after the prefix for the 654 // instruction it is bound to. 655 if (((CodeAddress) insn).getBindsClosely()) { 656 closelyBoundAddresses.add((CodeAddress)insn); 657 continue; 658 } 659 } 660 661 if (prefix != null) { 662 result.add(prefix); 663 } 664 665 // Add any pending closely bound addresses 666 if (!(insn instanceof ZeroSizeInsn) && closelyBoundAddresses.size() > 0) { 667 for (CodeAddress codeAddress: closelyBoundAddresses) { 668 result.add(codeAddress); 669 } 670 closelyBoundAddresses.clear(); 671 } 672 673 if (currentOpcode != originalOpcode) { 674 insn = insn.withOpcode(currentOpcode); 675 } 676 result.add(insn); 677 678 if (suffix != null) { 679 result.add(suffix); 680 } 681 } 682 683 return result; 684 } 685 686 /** 687 * Helper for {@link #finishProcessingAndGetList}, which assigns 688 * addresses to each instruction, possibly rewriting branches to 689 * fix ones that wouldn't otherwise be able to reach their 690 * targets. 691 */ 692 private void assignAddressesAndFixBranches() { 693 for (;;) { 694 assignAddresses(); 695 if (!fixBranches()) { 696 break; 697 } 698 } 699 } 700 701 /** 702 * Helper for {@link #assignAddressesAndFixBranches}, which 703 * assigns an address to each instruction, in order. 704 */ 705 private void assignAddresses() { 706 int address = 0; 707 int size = insns.size(); 708 709 for (int i = 0; i < size; i++) { 710 DalvInsn insn = insns.get(i); 711 insn.setAddress(address); 712 address += insn.codeSize(); 713 } 714 } 715 716 /** 717 * Helper for {@link #assignAddressesAndFixBranches}, which checks 718 * the branch target size requirement of each branch instruction 719 * to make sure it fits. For instructions that don't fit, this 720 * rewrites them to use a {@code goto} of some sort. In the 721 * case of a conditional branch that doesn't fit, the sense of the 722 * test is reversed in order to branch around a {@code goto} 723 * to the original target. 724 * 725 * @return whether any branches had to be fixed 726 */ 727 private boolean fixBranches() { 728 int size = insns.size(); 729 boolean anyFixed = false; 730 731 for (int i = 0; i < size; i++) { 732 DalvInsn insn = insns.get(i); 733 if (!(insn instanceof TargetInsn)) { 734 // This loop only needs to inspect TargetInsns. 735 continue; 736 } 737 738 Dop opcode = insn.getOpcode(); 739 TargetInsn target = (TargetInsn) insn; 740 741 if (opcode.getFormat().branchFits(target)) { 742 continue; 743 } 744 745 if (opcode.getFamily() == Opcodes.GOTO) { 746 // It is a goto; widen it if possible. 747 opcode = findOpcodeForInsn(insn, opcode); 748 if (opcode == null) { 749 /* 750 * The branch is already maximally large. This should 751 * only be possible if a method somehow manages to have 752 * more than 2^31 code units. 753 */ 754 throw new UnsupportedOperationException("method too long"); 755 } 756 insns.set(i, insn.withOpcode(opcode)); 757 } else { 758 /* 759 * It is a conditional: Reverse its sense, and arrange for 760 * it to branch around an absolute goto to the original 761 * branch target. 762 * 763 * Note: An invariant of the list being processed is 764 * that every TargetInsn is followed by a CodeAddress. 765 * Hence, it is always safe to get the next element 766 * after a TargetInsn and cast it to CodeAddress, as 767 * is happening a few lines down. 768 * 769 * Also note: Size gets incremented by one here, as we 770 * have -- in the net -- added one additional element 771 * to the list, so we increment i to match. The added 772 * and changed elements will be inspected by a repeat 773 * call to this method after this invocation returns. 774 */ 775 CodeAddress newTarget; 776 try { 777 newTarget = (CodeAddress) insns.get(i + 1); 778 } catch (IndexOutOfBoundsException ex) { 779 // The TargetInsn / CodeAddress invariant was violated. 780 throw new IllegalStateException( 781 "unpaired TargetInsn (dangling)"); 782 } catch (ClassCastException ex) { 783 // The TargetInsn / CodeAddress invariant was violated. 784 throw new IllegalStateException("unpaired TargetInsn"); 785 } 786 TargetInsn gotoInsn = 787 new TargetInsn(Dops.GOTO, target.getPosition(), 788 RegisterSpecList.EMPTY, target.getTarget()); 789 insns.set(i, gotoInsn); 790 insns.add(i, target.withNewTargetAndReversed(newTarget)); 791 size++; 792 i++; 793 } 794 795 anyFixed = true; 796 } 797 798 return anyFixed; 799 } 800 801 private void align64bits(Dop[] opcodes) { 802 while (true) { 803 int notAligned64bitRegAccess = 0; 804 int aligned64bitRegAccess = 0; 805 int notAligned64bitParamAccess = 0; 806 int aligned64bitParamAccess = 0; 807 int lastParameter = unreservedRegCount + reservedCount + reservedParameterCount; 808 int firstParameter = lastParameter - paramSize; 809 810 // Collects the number of time that 64-bit registers are accessed aligned or not. 811 for (DalvInsn insn : insns) { 812 RegisterSpecList regs = insn.getRegisters(); 813 for (int usedRegIdx = 0; usedRegIdx < regs.size(); usedRegIdx++) { 814 RegisterSpec reg = regs.get(usedRegIdx); 815 if (reg.isCategory2()) { 816 boolean isParameter = reg.getReg() >= firstParameter; 817 if (reg.isEvenRegister()) { 818 if (isParameter) { 819 aligned64bitParamAccess++; 820 } else { 821 aligned64bitRegAccess++; 822 } 823 } else { 824 if (isParameter) { 825 notAligned64bitParamAccess++; 826 } else { 827 notAligned64bitRegAccess++; 828 } 829 } 830 } 831 } 832 } 833 834 if (notAligned64bitParamAccess > aligned64bitParamAccess 835 && notAligned64bitRegAccess > aligned64bitRegAccess) { 836 addReservedRegisters(1); 837 } else if (notAligned64bitParamAccess > aligned64bitParamAccess) { 838 addReservedParameters(1); 839 } else if (notAligned64bitRegAccess > aligned64bitRegAccess) { 840 addReservedRegisters(1); 841 842 // Need to shift parameters if they exist and if number of unaligned is greater than 843 // aligned. We test the opposite because we previously shift all registers by one, 844 // so the number of aligned become the number of unaligned. 845 if (paramSize != 0 && aligned64bitParamAccess > notAligned64bitParamAccess) { 846 addReservedParameters(1); 847 } 848 } else { 849 break; 850 } 851 852 if (!reserveRegisters(opcodes)) { 853 break; 854 } 855 } 856 } 857 858 private void addReservedParameters(int delta) { 859 shiftParameters(delta); 860 reservedParameterCount += delta; 861 } 862 863 private void addReservedRegisters(int delta) { 864 shiftAllRegisters(delta); 865 reservedCount += delta; 866 } 867 868 private void shiftAllRegisters(int delta) { 869 int insnSize = insns.size(); 870 871 for (int i = 0; i < insnSize; i++) { 872 DalvInsn insn = insns.get(i); 873 // Since there is no need to replace CodeAddress since it does not use registers, skips it to 874 // avoid to update all TargetInsn that contain a reference to CodeAddress 875 if (!(insn instanceof CodeAddress)) { 876 insns.set(i, insn.withRegisterOffset(delta)); 877 } 878 } 879 } 880 881 private void shiftParameters(int delta) { 882 int insnSize = insns.size(); 883 int lastParameter = unreservedRegCount + reservedCount + reservedParameterCount; 884 int firstParameter = lastParameter - paramSize; 885 886 BasicRegisterMapper mapper = new BasicRegisterMapper(lastParameter); 887 for (int i = 0; i < lastParameter; i++) { 888 if (i >= firstParameter) { 889 mapper.addMapping(i, i + delta, 1); 890 } else { 891 mapper.addMapping(i, i, 1); 892 } 893 } 894 895 for (int i = 0; i < insnSize; i++) { 896 DalvInsn insn = insns.get(i); 897 // Since there is no need to replace CodeAddress since it does not use registers, skips it to 898 // avoid to update all TargetInsn that contain a reference to CodeAddress 899 if (!(insn instanceof CodeAddress)) { 900 insns.set(i, insn.withMapper(mapper)); 901 } 902 } 903 } 904} 905