1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.code;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.LocalItem;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpec;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecList;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecSet;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SourcePosition;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Constant;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstMemberRef;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.HashSet;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Processor for instruction lists, which takes a "first cut" of
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * instruction selection as a basis and produces a "final cut" in the
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * form of a {@link DalvInsnList} instance.
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class OutputFinisher {
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code >= 0;} register count for the method, not including any extra
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * "reserved" registers needed to translate "difficult" instructions
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int unreservedRegCount;
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} the list of instructions, per se */
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private ArrayList<DalvInsn> insns;
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** whether any instruction has position info */
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private boolean hasAnyPositionInfo;
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** whether any instruction has local variable info */
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private boolean hasAnyLocalInfo;
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code >= 0;} the count of reserved registers (low-numbered
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * registers used when expanding instructions that can't be
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * represented simply); becomes valid after a call to {@link
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * #massageInstructions}
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int reservedCount;
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. It initially contains no instructions.
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param regCount {@code >= 0;} register count for the method
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param initialCapacity {@code >= 0;} initial capacity of the instructions
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * list
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public OutputFinisher(int initialCapacity, int regCount) {
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.unreservedRegCount = regCount;
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.insns = new ArrayList<DalvInsn>(initialCapacity);
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.reservedCount = -1;
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.hasAnyPositionInfo = false;
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.hasAnyLocalInfo = false;
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns whether any of the instructions added to this instance
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * come with position info.
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return whether any of the instructions added to this instance
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * come with position info
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public boolean hasAnyPositionInfo() {
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return hasAnyPositionInfo;
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns whether this instance has any local variable information.
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return whether this instance has any local variable information
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public boolean hasAnyLocalInfo() {
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return hasAnyLocalInfo;
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #add} which scrutinizes a single
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instruction for local variable information.
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} instruction to scrutinize
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code true} iff the instruction refers to any
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * named locals
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static boolean hasLocalInfo(DalvInsn insn) {
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (insn instanceof LocalSnapshot) {
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int size = specs.size();
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < size; i++) {
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (hasLocalInfo(specs.get(i))) {
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    return true;
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else if (insn instanceof LocalStart) {
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec spec = ((LocalStart) insn).getLocal();
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (hasLocalInfo(spec)) {
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return true;
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return false;
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * register spec.
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param spec {@code non-null;} spec to scrutinize
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code true} iff the spec refers to any
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * named locals
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static boolean hasLocalInfo(RegisterSpec spec) {
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (spec != null)
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            && (spec.getLocalItem().getName() != null);
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns the set of all constants referred to by instructions added
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * to this instance.
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the set of constants
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public HashSet<Constant> getAllConstants() {
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        HashSet<Constant> result = new HashSet<Constant>(20);
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (DalvInsn insn : insns) {
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addConstants(result, insn);
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #getAllConstants} which adds all the info for
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * a single instruction.
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param result {@code non-null;} result set to add to
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} instruction to scrutinize
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void addConstants(HashSet<Constant> result,
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn) {
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (insn instanceof CstInsn) {
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Constant cst = ((CstInsn) insn).getConstant();
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(cst);
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else if (insn instanceof LocalSnapshot) {
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpecSet specs = ((LocalSnapshot) insn).getLocals();
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int size = specs.size();
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < size; i++) {
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addConstants(result, specs.get(i));
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else if (insn instanceof LocalStart) {
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec spec = ((LocalStart) insn).getLocal();
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addConstants(result, spec);
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #getAllConstants} which adds all the info for
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * a single {@code RegisterSpec}.
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param result {@code non-null;} result set to add to
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param spec {@code null-ok;} register spec to add
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void addConstants(HashSet<Constant> result,
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec spec) {
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (spec == null) {
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return;
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        LocalItem local = spec.getLocalItem();
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstUtf8 name = local.getName();
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstUtf8 signature = local.getSignature();
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Type type = spec.getType();
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (type != Type.KNOWN_NULL) {
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(CstType.intern(type));
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (name != null) {
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(name);
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (signature != null) {
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(signature);
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Adds an instruction to the output.
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} the instruction to add
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void add(DalvInsn insn) {
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        insns.add(insn);
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        updateInfo(insn);
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Inserts an instruction in the output at the given offset.
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param at {@code >= 0;} what index to insert at
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} the instruction to insert
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void insert(int at, DalvInsn insn) {
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        insns.add(at, insn);
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        updateInfo(insn);
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #add} and {@link #insert},
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * which updates the position and local info flags.
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} an instruction that was just introduced
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void updateInfo(DalvInsn insn) {
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (! hasAnyPositionInfo) {
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (pos.getLine() >= 0) {
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                hasAnyPositionInfo = true;
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (! hasAnyLocalInfo) {
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (hasLocalInfo(insn)) {
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                hasAnyLocalInfo = true;
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Reverses a branch which is buried a given number of instructions
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * backward in the output. It is illegal to call this unless the
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * indicated instruction really is a reversible branch.
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param which how many instructions back to find the branch;
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code 0} is the most recently added instruction,
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code 1} is the instruction before that, etc.
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param newTarget {@code non-null;} the new target for the reversed branch
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void reverseBranch(int which, CodeAddress newTarget) {
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int index = size - which - 1;
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        TargetInsn targetInsn;
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            targetInsn = (TargetInsn) insns.get(index);
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (IndexOutOfBoundsException ex) {
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Translate the exception.
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("too few instructions");
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (ClassCastException ex) {
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Translate the exception.
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("non-reversible instruction");
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * No need to call this.set(), since the format and other info
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * are the same.
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        insns.set(index, targetInsn.withNewTargetAndReversed(newTarget));
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Assigns indices in all instructions that need them, using the
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * given callback to perform lookups. This should be called before
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * calling {@link #finishProcessingAndGetList}.
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param callback {@code non-null;} callback object
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void assignIndices(DalvCode.AssignIndicesCallback callback) {
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (DalvInsn insn : insns) {
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (insn instanceof CstInsn) {
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                assignIndices((CstInsn) insn, callback);
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #assignIndices} which does assignment for one
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instruction.
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} the instruction
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param callback {@code non-null;} the callback
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void assignIndices(CstInsn insn,
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvCode.AssignIndicesCallback callback) {
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Constant cst = insn.getConstant();
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int index = callback.getIndex(cst);
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (index >= 0) {
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            insn.setIndex(index);
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (cst instanceof CstMemberRef) {
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CstMemberRef member = (CstMemberRef) cst;
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CstType definer = member.getDefiningClass();
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            index = callback.getIndex(definer);
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (index >= 0) {
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insn.setClassIndex(index);
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Does final processing on this instance and gets the output as
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * a {@link DalvInsnList}. Final processing consists of:
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <ul>
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   <li>optionally renumbering registers (to make room as needed for
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   expanded instructions)</li>
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   <li>picking a final opcode for each instruction</li>
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   <li>rewriting instructions, because of register number,
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   constant pool index, or branch target size issues</li>
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *   <li>assigning final addresses</li>
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * </ul>
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <p><b>Note:</b> This method may only be called once per instance
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * of this class.</p>
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the output list
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws UnsupportedOperationException if this method has
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * already been called
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public DalvInsnList finishProcessingAndGetList() {
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (reservedCount >= 0) {
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new UnsupportedOperationException("already processed");
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        InsnFormat[] formats = makeFormatsArray();
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        reserveRegisters(formats);
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        massageInstructions(formats);
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        assignAddressesAndFixBranches();
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return DalvInsnList.makeImmutable(insns,
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                reservedCount + unreservedRegCount);
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #finishProcessingAndGetList}, which extracts
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the format out of each instruction into a separate array, to be
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * further manipulated as things progress.
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the array of formats
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private InsnFormat[] makeFormatsArray() {
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        InsnFormat[] result = new InsnFormat[size];
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result[i] = insns.get(i).getOpcode().getFormat();
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #finishProcessingAndGetList}, which figures
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * out how many reserved registers are required and then reserving
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * them. It also updates the given {@code formats} array so
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * as to avoid extra work when constructing the massaged
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instruction list.
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param formats {@code non-null;} array of per-instruction format selections
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void reserveRegisters(InsnFormat[] formats) {
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Call calculateReservedCount() and then perform register
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * reservation, repeatedly until no new reservations happen.
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int newReservedCount = calculateReservedCount(formats);
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (oldReservedCount >= newReservedCount) {
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int reservedDifference = newReservedCount - oldReservedCount;
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int size = insns.size();
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < size; i++) {
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * CodeAddress instance identity is used to link
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * TargetInsns to their targets, so it is
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * inappropriate to make replacements, and they don't
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * have registers in any case. Hence, the instanceof
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * test below.
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                DalvInsn insn = insns.get(i);
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (!(insn instanceof CodeAddress)) {
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * No need to call this.set() since the format and
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * other info are the same.
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    insns.set(i, insn.withRegisterOffset(reservedDifference));
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            oldReservedCount = newReservedCount;
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        reservedCount = oldReservedCount;
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #reserveRegisters}, which does one
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * pass over the instructions, calculating the number of
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * registers that need to be reserved. It also updates the
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code formats} list to help avoid extra work in future
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * register reservation passes.
430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param formats {@code non-null;} array of per-instruction format selections
432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code >= 0;} the count of reserved registers
433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int calculateReservedCount(InsnFormat[] formats) {
435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Potential new value of reservedCount, which gets updated in the
439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * following loop. It starts out with the existing reservedCount
440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and gets increased if it turns out that additional registers
441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * need to be reserved.
442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int newReservedCount = reservedCount;
444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn = insns.get(i);
447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            InsnFormat originalFormat = formats[i];
448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            InsnFormat newFormat = findFormatForInsn(insn, originalFormat);
449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (originalFormat == newFormat) {
451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (newFormat == null) {
455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * The instruction will need to be expanded, so reserve
457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * registers for it.
458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int reserve = insn.getMinimumRegisterRequirement();
460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (reserve > newReservedCount) {
461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    newReservedCount = reserve;
462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            formats[i] = newFormat;
466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return newReservedCount;
469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Attempts to fit the given instruction into a format, returning
473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * either a format that the instruction fits into or {@code null}
474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * to indicate that the instruction will need to be expanded. This
475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * fitting process starts with the given format as a first "best
476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * guess" and then pessimizes from there if necessary.
477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} the instruction in question
479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param format {@code null-ok;} the current guess as to the best instruction
480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * format to use; {@code null} means that no simple format fits
481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code null-ok;} a possibly-different format, which is either a
482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * good fit or {@code null} to indicate that no simple format
483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * fits
484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private InsnFormat findFormatForInsn(DalvInsn insn, InsnFormat format) {
486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (format == null) {
487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // The instruction is already known not to fit any simple format.
488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return format;
489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (format.isCompatible(insn)) {
492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // The instruction already fits in the current best-known format.
493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return format;
494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Dop dop = insn.getOpcode();
497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int family = dop.getFamily();
498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            format = format.nextUp();
501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((format == null) ||
502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    (format.isCompatible(insn) &&
503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     (Dops.getOrNull(family, format) != null))) {
504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return format;
509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #finishProcessingAndGetList}, which goes
513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * through each instruction in the output, making sure its opcode
514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * can accomodate its arguments. In cases where the opcode is
515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * unable to do so, this replaces the instruction with a larger
516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instruction with identical semantics that <i>will</i> work.
517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <p>This method may also reserve a number of low-numbered
519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * registers, renumbering the instructions' original registers, in
520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * order to have register space available in which to move
521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * very-high registers when expanding instructions into
522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * multi-instruction sequences. This expansion is done when no
523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * simple instruction format can be found for a given instruction that
524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * is able to accomodate that instruction's registers.</p>
525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * <p>This method ignores issues of branch target size, since
527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * final addresses aren't known at the point that this method is
528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * called.</p>
529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param formats {@code non-null;} array of per-instruction format selections
531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void massageInstructions(InsnFormat[] formats) {
533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (reservedCount == 0) {
534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The easy common case: No registers were reserved, so we
536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * merely need to replace any instructions whose format changed
537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * during the reservation pass, but all instructions will stay
538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * at their original indices, and the instruction list doesn't
539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * grow.
540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int size = insns.size();
542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < size; i++) {
544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                DalvInsn insn = insns.get(i);
545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Dop dop = insn.getOpcode();
546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                InsnFormat format = formats[i];
547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (format != dop.getFormat()) {
549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    dop = Dops.getOrNull(dop.getFamily(), format);
550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    insns.set(i, insn.withOpcode(dop));
551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The difficult uncommon case: Some instructions have to be
556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * expanded to deal with high registers.
557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            insns = performExpansion(formats);
559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #massageInstructions}, which constructs a
564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * replacement list, where each {link DalvInsn} instance that
565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * couldn't be represented simply (due to register representation
566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * problems) is expanded into a series of instances that together
567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * perform the proper function.
568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param formats {@code non-null;} array of per-instruction format selections
570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the replacement list
571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) {
573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn = insns.get(i);
578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop dop = insn.getOpcode();
579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            InsnFormat originalFormat = dop.getFormat();
580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            InsnFormat currentFormat = formats[i];
581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn prefix;
582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn suffix;
583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (currentFormat != null) {
585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // No expansion is necessary.
586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                prefix = null;
587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                suffix = null;
588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Expansion is required.
590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                prefix = insn.hrPrefix();
591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                suffix = insn.hrSuffix();
592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Get the initial guess as to the hr version, but then
595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * let findFormatForInsn() pick a better format, if any.
596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insn = insn.hrVersion();
598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                originalFormat = insn.getOpcode().getFormat();
599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                currentFormat = findFormatForInsn(insn, originalFormat);
600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (prefix != null) {
603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                result.add(prefix);
604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (currentFormat != originalFormat) {
607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                dop = Dops.getOrNull(dop.getFamily(), currentFormat);
608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insn = insn.withOpcode(dop);
609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(insn);
611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (suffix != null) {
613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                result.add(suffix);
614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #finishProcessingAndGetList}, which assigns
622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * addresses to each instruction, possibly rewriting branches to
623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * fix ones that wouldn't otherwise be able to reach their
624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * targets.
625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void assignAddressesAndFixBranches() {
627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            assignAddresses();
629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (!fixBranches()) {
630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #assignAddressesAndFixBranches}, which
637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * assigns an address to each instruction, in order.
638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void assignAddresses() {
640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int address = 0;
641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn = insns.get(i);
645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            insn.setAddress(address);
646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            address += insn.codeSize();
647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #assignAddressesAndFixBranches}, which checks
652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the branch target size requirement of each branch instruction
653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * to make sure it fits. For instructions that don't fit, this
654917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * rewrites them to use a {@code goto} of some sort. In the
655917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * case of a conditional branch that doesn't fit, the sense of the
656917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * test is reversed in order to branch around a {@code goto}
657917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * to the original target.
658917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
659917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return whether any branches had to be fixed
660917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
661917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private boolean fixBranches() {
662917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = insns.size();
663917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean anyFixed = false;
664917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
665917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
666917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn = insns.get(i);
667917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (!(insn instanceof TargetInsn)) {
668917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // This loop only needs to inspect TargetInsns.
669917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
670917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
671917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
672917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop dop = insn.getOpcode();
673917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            InsnFormat format = dop.getFormat();
674917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            TargetInsn target = (TargetInsn) insn;
675917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
676917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (format.branchFits(target)) {
677917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
678917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
679917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
680917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (dop.getFamily() == DalvOps.GOTO) {
681917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // It is a goto; widen it if possible.
682917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                InsnFormat newFormat = findFormatForInsn(insn, format);
683917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (newFormat == null) {
684917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
685917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * The branch is already maximally large. This should
686917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * only be possible if a method somehow manages to have
687917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * more than 2^31 code units.
688917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
689917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new UnsupportedOperationException("method too long");
690917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
691917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                dop = Dops.getOrNull(dop.getFamily(), newFormat);
692917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insn = insn.withOpcode(dop);
693917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insns.set(i, insn);
694917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
695917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
696917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * It is a conditional: Reverse its sense, and arrange for
697917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * it to branch around an absolute goto to the original
698917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * branch target.
699917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 *
700917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Note: An invariant of the list being processed is
701917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * that every TargetInsn is followed by a CodeAddress.
702917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Hence, it is always safe to get the next element
703917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * after a TargetInsn and cast it to CodeAddress, as
704917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * is happening a few lines down.
705917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 *
706917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Also note: Size gets incremented by one here, as we
707917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * have -- in the net -- added one additional element
708917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * to the list, so we increment i to match. The added
709917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * and changed elements will be inspected by a repeat
710917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * call to this method after this invocation returns.
711917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
712917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                CodeAddress newTarget;
713917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                try {
714917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    newTarget = (CodeAddress) insns.get(i + 1);
715917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } catch (IndexOutOfBoundsException ex) {
716917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    // The TargetInsn / CodeAddress invariant was violated.
717917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new IllegalStateException(
718917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            "unpaired TargetInsn (dangling)");
719917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } catch (ClassCastException ex) {
720917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    // The TargetInsn / CodeAddress invariant was violated.
721917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new IllegalStateException("unpaired TargetInsn");
722917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
723917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                TargetInsn gotoInsn =
724917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    new TargetInsn(Dops.GOTO, target.getPosition(),
725917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            RegisterSpecList.EMPTY, target.getTarget());
726917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insns.set(i, gotoInsn);
727917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                insns.add(i, target.withNewTargetAndReversed(newTarget));
728917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                size++;
729917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                i++;
730917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
731917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
732917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            anyFixed = true;
733917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
734917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
735917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return anyFixed;
736917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
737917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
738