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