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