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